diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000000..c5d209fb1fda5 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,21 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.192.0/containers/dotnet/.devcontainer/base.Dockerfile + +# [Choice] .NET version: 6.0, 5.0, 3.1, 2.1 +ARG VARIANT="6.0" +FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT} + +# Set up machine requirements to build the repo +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends cmake llvm-9 clang-9 \ + build-essential python curl git lldb-6.0 liblldb-6.0-dev \ + libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev \ + libssl-dev libnuma-dev libkrb5-dev zlib1g-dev ninja-build + +# Install V8 Engine +SHELL ["/bin/bash", "-c"] + +RUN curl -sSL "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/linux/chromium-v8/v8-linux64-rel-8.5.183.zip" -o ./v8.zip \ + && unzip ./v8.zip -d /usr/local/v8 \ + && echo $'#!/usr/bin/env bash\n\ +"/usr/local/v8/d8" --snapshot_blob="/usr/local/v8/snapshot_blob.bin" "$@"\n' > /usr/local/bin/v8 \ + && chmod +x /usr/local/bin/v8 \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000000..5b1306e10f8a6 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,57 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/dotnetcore +{ + "name": "C# (.NET 6)", + "build": { + "dockerfile": "Dockerfile", + "args": { + "VARIANT": "6.0", + } + }, + "settings": { + "files.associations": { + "*.csproj": "msbuild", + "*.fsproj": "msbuild", + "*.globalconfig": "ini", + "*.manifest": "xml", + "*.nuspec": "xml", + "*.pkgdef": "ini", + "*.projitems": "msbuild", + "*.props": "msbuild", + "*.resx": "xml", + "*.rsp": "Powershell", + "*.ruleset": "xml", + "*.settings": "xml", + "*.shproj": "msbuild", + "*.slnf": "json", + "*.targets": "msbuild", + "*.vbproj": "msbuild", + "*.vsixmanifest": "xml", + "*.vstemplate": "xml", + "*.xlf": "xml", + "*.yml": "azure-pipelines" + }, + // ms-dotnettools.csharp settings + "omnisharp.defaultLaunchSolution": "Compilers.sln", + "omnisharp.disableMSBuildDiagnosticWarning": true, + "omnisharp.enableEditorConfigSupport": true, + "omnisharp.enableImportCompletion": true, + "omnisharp.enableRoslynAnalyzers": true, + "omnisharp.useModernNet": true, + "omnisharp.enableAsyncCompletion": true, + // ms-vscode.powershell settings + "powershell.promptToUpdatePowerShell": false, + "powershell.integratedConsole.showOnStartup": false, + "powershell.startAutomatically": false, + // ms-azure-devops.azure-pipelines settings + "azure-pipelines.customSchemaFile": ".vscode/dnceng-schema.json" + }, + "extensions": [ + "ms-dotnettools.csharp", + "EditorConfig.EditorConfig", + "ms-vscode.powershell", + "tintoy.msbuild-project-tools", + "ms-azure-devops.azure-pipelines" + ], + "postCreateCommand": "${containerWorkspaceFolder}/restore.sh" +} \ No newline at end of file diff --git a/.devcontainer/devinit.json b/.devcontainer/devinit.json new file mode 100644 index 0000000000000..b88bf48be143c --- /dev/null +++ b/.devcontainer/devinit.json @@ -0,0 +1,7 @@ +{ + "run": [ + { + "tool": "require-dotnetcoresdk" + } + ] + } \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 7ff7c2c3d8ba9..54698466925f7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -301,6 +301,5 @@ dotnet_diagnostic.IDE2004.severity = warning [src/{VisualStudio}/**/*.{cs,vb}] # CA1822: Make member static -# Not enforced as a build 'warning' for 'VisualStudio' layer due to large number of false positives from https://github.com/dotnet/roslyn-analyzers/issues/3857 and https://github.com/dotnet/roslyn-analyzers/issues/3858 -# Additionally, there is a risk of accidentally breaking an internal API that partners rely on though IVT. -dotnet_diagnostic.CA1822.severity = suggestion +# There is a risk of accidentally breaking an internal API that partners rely on though IVT. +dotnet_code_quality.CA1822.api_surface = private diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b0020afd6216a..8be9f768ee90d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,9 +3,14 @@ *.yml @dotnet/roslyn-infrastructure .github/ @dotnet/roslyn-infrastructure + +docs/compilers @dotnet/roslyn-compiler +docs/ide @dotnet/roslyn-ide + eng/ @dotnet/roslyn-infrastructure scripts/ @dotnet/roslyn-infrastructure +src/Analyzers/ @dotnet/roslyn-ide src/CodeStyle/ @dotnet/roslyn-ide src/Compilers/ @dotnet/roslyn-compiler # Both IDE and Compiler traits are in this file, so we don't want to ping each other for changes to just this file. diff --git a/.github/ISSUE_TEMPLATE/analyzer-suggestion.md b/.github/ISSUE_TEMPLATE/analyzer-suggestion.md index bc850e748186b..6c089d0ca6827 100644 --- a/.github/ISSUE_TEMPLATE/analyzer-suggestion.md +++ b/.github/ISSUE_TEMPLATE/analyzer-suggestion.md @@ -1,12 +1,15 @@ --- name: Analyzer suggestion -about: Suggest a Roslyn analyzer related to code style. Semantic/code quality analyzers are developed in roslyn-analyzers repository. +about: Suggest a Roslyn analyzer related to code style. labels: [Area-IDE, Feature Request] --- + + + **Brief description:** -Describe your suggestion here. +Describe your **code style** rule here. **Languages applicable:** diff --git a/.github/ISSUE_TEMPLATE/api-suggestion.md b/.github/ISSUE_TEMPLATE/api-suggestion.md index 5f6beb1283322..1892072485d52 100644 --- a/.github/ISSUE_TEMPLATE/api-suggestion.md +++ b/.github/ISSUE_TEMPLATE/api-suggestion.md @@ -37,10 +37,11 @@ namespace Microsoft.CodeAnalysis.Operations Please provide code examples that highlight how the proposed API additions are meant to be consumed. This will help suggest whether the API has the right shape to be functional, performant and useable. You can use code blocks like this: +--> + ``` C# // some lines of code here ``` ---> ## Alternative Designs diff --git a/.vscode/dnceng-schema.json b/.vscode/dnceng-schema.json new file mode 100644 index 0000000000000..cc0f88ba48e96 --- /dev/null +++ b/.vscode/dnceng-schema.json @@ -0,0 +1 @@ +{"$schema":"http://json-schema.org/draft-07/schema#","$id":"https://github.com/Microsoft/azure-pipelines-vscode/blob/main/service-schema.json","$comment":"v1.183.0","title":"Pipeline schema","description":"A pipeline definition","oneOf":[{"$ref":"#/definitions/pipeline"},{"type":"string","pattern":"^$"}],"definitions":{"string":{"type":"string"},"sequence":{"type":"array","items":{"$ref":"#/definitions/any"}},"mapping":{"type":"object","additionalProperties":true},"any":{"anyOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/definitions/any"}},{"type":"object","additionalProperties":true}]},"pipeline":{"anyOf":[{"type":"object","properties":{"stages":{"description":"Stages are groups of jobs that can run without human intervention","$ref":"#/definitions/stages"},"pool":{"description":"Pool where jobs in this pipeline will run unless otherwise specified","$ref":"#/definitions/pool"},"name":{"description":"Pipeline name","$ref":"#/definitions/string_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/trigger"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/pipelineTemplateParameters"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/pr"},"schedules":{"$ref":"#/definitions/schedules"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/resources"},"variables":{"description":"Variables for this pipeline","$ref":"#/definitions/variables"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false,"required":["stages"]},{"type":"object","properties":{"extends":{"description":"Extends a template","$ref":"#/definitions/extends"},"pool":{"description":"Pool where jobs in this pipeline will run unless otherwise specified","$ref":"#/definitions/pool"},"name":{"description":"Pipeline name","$ref":"#/definitions/string_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/trigger"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/pipelineTemplateParameters"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/pr"},"schedules":{"$ref":"#/definitions/schedules"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/resources"},"variables":{"description":"Variables for this pipeline","$ref":"#/definitions/variables"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false,"required":["extends"]},{"type":"object","properties":{"jobs":{"description":"Jobs represent units of work which can be assigned to a single agent or server","$ref":"#/definitions/jobs"},"pool":{"description":"Pool where jobs in this pipeline will run unless otherwise specified","$ref":"#/definitions/pool"},"name":{"description":"Pipeline name","$ref":"#/definitions/string_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/trigger"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/pipelineTemplateParameters"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/pr"},"schedules":{"$ref":"#/definitions/schedules"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/resources"},"variables":{"description":"Variables for this pipeline","$ref":"#/definitions/variables"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false,"required":["jobs"]},{"type":"object","properties":{"phases":{"description":"Phases which make up the pipeline","deprecationMessage":"This option is deprecated, use `jobs` instead","doNotSuggest":true,"$ref":"#/definitions/phases"},"name":{"description":"Pipeline name","$ref":"#/definitions/string_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/trigger"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/pipelineTemplateParameters"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/pr"},"schedules":{"$ref":"#/definitions/schedules"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/resources"},"variables":{"description":"Variables for this pipeline","$ref":"#/definitions/variables"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false,"required":["phases"]},{"type":"object","properties":{"strategy":{"description":"Execution strategy for this job","$ref":"#/definitions/jobStrategy"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/jobContinueOnError"},"pool":{"description":"Pool where this job will run","$ref":"#/definitions/pool"},"container":{"description":"Container resource name","$ref":"#/definitions/jobContainer"},"services":{"$ref":"#/definitions/jobServices"},"workspace":{"$ref":"#/definitions/jobWorkspace"},"steps":{"description":"A list of steps to run in this job","$ref":"#/definitions/steps"},"name":{"description":"Pipeline name","$ref":"#/definitions/string_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/trigger"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/pipelineTemplateParameters"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/pr"},"schedules":{"$ref":"#/definitions/schedules"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/resources"},"variables":{"description":"Variables for this pipeline","$ref":"#/definitions/variables"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false,"required":["steps"]},{"type":"object","properties":{"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/jobContinueOnError"},"queue":{"description":"Queue where this phase will run","deprecationMessage":"This option is deprecated, use pool instead","doNotSuggest":true,"$ref":"#/definitions/phaseQueueTarget"},"steps":{"description":"A list of steps to run in this phase","$ref":"#/definitions/steps"},"name":{"description":"Pipeline name","$ref":"#/definitions/string_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/trigger"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/pipelineTemplateParameters"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/pr"},"schedules":{"$ref":"#/definitions/schedules"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/resources"},"variables":{"description":"Variables for this pipeline","$ref":"#/definitions/variables"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false,"deprecationMessage":"This option is deprecated, use `job` (inside `jobs`) instead","required":["steps"]},{"type":"object","properties":{"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/jobContinueOnError"},"server":{"description":"True if this is an agent-less phase (runs on server)","deprecationMessage":"This option is deprecated, use pool:server instead","doNotSuggest":true,"$ref":"#/definitions/phaseServerTarget"},"steps":{"description":"A list of steps to run in this phase","$ref":"#/definitions/steps"},"name":{"description":"Pipeline name","$ref":"#/definitions/string_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/trigger"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/pipelineTemplateParameters"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/pr"},"schedules":{"$ref":"#/definitions/schedules"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/resources"},"variables":{"description":"Variables for this pipeline","$ref":"#/definitions/variables"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false,"deprecationMessage":"This option is deprecated, use `job` (inside `jobs`) instead","required":["steps"]}]},"pipelineBase":{"type":"object","properties":{"name":{"description":"Pipeline name","$ref":"#/definitions/string_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/trigger"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/pipelineTemplateParameters"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/pr"},"schedules":{"$ref":"#/definitions/schedules"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/resources"},"variables":{"description":"Variables for this pipeline","$ref":"#/definitions/variables"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false},"pipelineTrigger":{"type":"object","properties":{"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/trigger"},"name":{"description":"Pipeline name","$ref":"#/definitions/any_allowExpressions"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/any_allowExpressions"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/any_allowExpressions"},"schedules":{"$ref":"#/definitions/any_allowExpressions"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/any_allowExpressions"},"variables":{"description":"Variables for the entire pipeline","$ref":"#/definitions/any_allowExpressions"},"stages":{"$ref":"#/definitions/any_allowExpressions"},"jobs":{"description":"Jobs which make up the pipeline","$ref":"#/definitions/any_allowExpressions"},"extends":{"description":"Extends a template","$ref":"#/definitions/any_allowExpressions"},"phases":{"description":"Phases which make up the pipeline","deprecationMessage":"This option is deprecated, use `jobs` instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"strategy":{"description":"Execution strategy for the job","$ref":"#/definitions/any_allowExpressions"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/any_allowExpressions"},"pool":{"description":"Pool where this job will run","$ref":"#/definitions/any_allowExpressions"},"container":{"description":"Container resource name","$ref":"#/definitions/any_allowExpressions"},"services":{"$ref":"#/definitions/any_allowExpressions"},"workspace":{"$ref":"#/definitions/any_allowExpressions"},"steps":{"description":"A list of steps to run","$ref":"#/definitions/any_allowExpressions"},"queue":{"description":"Queue where this phase will run","deprecationMessage":"This option is deprecated, use pool instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"server":{"description":"True if this is an agent-less phase (runs on server)","deprecationMessage":"This option is deprecated, use pool:server instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false},"pipelineParameters":{"type":"object","properties":{"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/pipelineTemplateParameters"},"name":{"description":"Pipeline name","$ref":"#/definitions/any_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/any_allowExpressions"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/any_allowExpressions"},"schedules":{"$ref":"#/definitions/any_allowExpressions"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/any_allowExpressions"},"variables":{"description":"Variables for the entire pipeline","$ref":"#/definitions/any_allowExpressions"},"stages":{"$ref":"#/definitions/any_allowExpressions"},"jobs":{"description":"Jobs which make up the pipeline","$ref":"#/definitions/any_allowExpressions"},"extends":{"description":"Extends a template","$ref":"#/definitions/any_allowExpressions"},"phases":{"description":"Phases which make up the pipeline","deprecationMessage":"This option is deprecated, use `jobs` instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"strategy":{"description":"Execution strategy for the job","$ref":"#/definitions/any_allowExpressions"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/any_allowExpressions"},"pool":{"description":"Pool where this job will run","$ref":"#/definitions/any_allowExpressions"},"container":{"description":"Container resource name","$ref":"#/definitions/any_allowExpressions"},"services":{"$ref":"#/definitions/any_allowExpressions"},"workspace":{"$ref":"#/definitions/any_allowExpressions"},"steps":{"description":"A list of steps to run","$ref":"#/definitions/any_allowExpressions"},"queue":{"description":"Queue where this phase will run","deprecationMessage":"This option is deprecated, use pool instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"server":{"description":"True if this is an agent-less phase (runs on server)","deprecationMessage":"This option is deprecated, use pool:server instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false},"pipelinePR":{"type":"object","properties":{"pr":{"description":"Pull request triggers","$ref":"#/definitions/pr"},"name":{"description":"Pipeline name","$ref":"#/definitions/any_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/any_allowExpressions"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/any_allowExpressions"},"schedules":{"$ref":"#/definitions/any_allowExpressions"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/any_allowExpressions"},"variables":{"description":"Variables for the entire pipeline","$ref":"#/definitions/any_allowExpressions"},"stages":{"$ref":"#/definitions/any_allowExpressions"},"jobs":{"description":"Jobs which make up the pipeline","$ref":"#/definitions/any_allowExpressions"},"extends":{"description":"Extends a template","$ref":"#/definitions/any_allowExpressions"},"phases":{"description":"Phases which make up the pipeline","deprecationMessage":"This option is deprecated, use `jobs` instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"strategy":{"description":"Execution strategy for the job","$ref":"#/definitions/any_allowExpressions"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/any_allowExpressions"},"pool":{"description":"Pool where this job will run","$ref":"#/definitions/any_allowExpressions"},"container":{"description":"Container resource name","$ref":"#/definitions/any_allowExpressions"},"services":{"$ref":"#/definitions/any_allowExpressions"},"workspace":{"$ref":"#/definitions/any_allowExpressions"},"steps":{"description":"A list of steps to run","$ref":"#/definitions/any_allowExpressions"},"queue":{"description":"Queue where this phase will run","deprecationMessage":"This option is deprecated, use pool instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"server":{"description":"True if this is an agent-less phase (runs on server)","deprecationMessage":"This option is deprecated, use pool:server instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false},"pipelineSchedules":{"type":"object","properties":{"schedules":{"$ref":"#/definitions/schedules"},"name":{"description":"Pipeline name","$ref":"#/definitions/any_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/any_allowExpressions"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/any_allowExpressions"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/any_allowExpressions"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/any_allowExpressions"},"variables":{"description":"Variables for the entire pipeline","$ref":"#/definitions/any_allowExpressions"},"stages":{"$ref":"#/definitions/any_allowExpressions"},"jobs":{"description":"Jobs which make up the pipeline","$ref":"#/definitions/any_allowExpressions"},"extends":{"description":"Extends a template","$ref":"#/definitions/any_allowExpressions"},"phases":{"description":"Phases which make up the pipeline","deprecationMessage":"This option is deprecated, use `jobs` instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"strategy":{"description":"Execution strategy for the job","$ref":"#/definitions/any_allowExpressions"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/any_allowExpressions"},"pool":{"description":"Pool where this job will run","$ref":"#/definitions/any_allowExpressions"},"container":{"description":"Container resource name","$ref":"#/definitions/any_allowExpressions"},"services":{"$ref":"#/definitions/any_allowExpressions"},"workspace":{"$ref":"#/definitions/any_allowExpressions"},"steps":{"description":"A list of steps to run","$ref":"#/definitions/any_allowExpressions"},"queue":{"description":"Queue where this phase will run","deprecationMessage":"This option is deprecated, use pool instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"server":{"description":"True if this is an agent-less phase (runs on server)","deprecationMessage":"This option is deprecated, use pool:server instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false},"pipelineAnyBase":{"type":"object","properties":{"name":{"description":"Pipeline name","$ref":"#/definitions/any_allowExpressions"},"trigger":{"description":"Continuous integration triggers","$ref":"#/definitions/any_allowExpressions"},"parameters":{"description":"Pipeline template parameters","$ref":"#/definitions/any_allowExpressions"},"pr":{"description":"Pull request triggers","$ref":"#/definitions/any_allowExpressions"},"schedules":{"$ref":"#/definitions/any_allowExpressions"},"resources":{"description":"Containers and repositories used in the build","$ref":"#/definitions/any_allowExpressions"},"variables":{"description":"Variables for the entire pipeline","$ref":"#/definitions/any_allowExpressions"},"stages":{"$ref":"#/definitions/any_allowExpressions"},"jobs":{"description":"Jobs which make up the pipeline","$ref":"#/definitions/any_allowExpressions"},"extends":{"description":"Extends a template","$ref":"#/definitions/any_allowExpressions"},"phases":{"description":"Phases which make up the pipeline","deprecationMessage":"This option is deprecated, use `jobs` instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"strategy":{"description":"Execution strategy for the job","$ref":"#/definitions/any_allowExpressions"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/any_allowExpressions"},"pool":{"description":"Pool where this job will run","$ref":"#/definitions/any_allowExpressions"},"container":{"description":"Container resource name","$ref":"#/definitions/any_allowExpressions"},"services":{"$ref":"#/definitions/any_allowExpressions"},"workspace":{"$ref":"#/definitions/any_allowExpressions"},"steps":{"description":"A list of steps to run","$ref":"#/definitions/any_allowExpressions"},"queue":{"description":"Queue where this phase will run","deprecationMessage":"This option is deprecated, use pool instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"server":{"description":"True if this is an agent-less phase (runs on server)","deprecationMessage":"This option is deprecated, use pool:server instead","doNotSuggest":true,"$ref":"#/definitions/any_allowExpressions"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false},"pr":{"anyOf":[{"type":"string","pattern":"^none$"},{"type":"array","items":{"$ref":"#/definitions/branchFilter"}},{"type":"object","properties":{"autoCancel":{"description":"Whether to cancel running PR builds when a new commit lands in the branch","$ref":"#/definitions/boolean"},"branches":{"$ref":"#/definitions/includeExcludeFilters"},"paths":{"$ref":"#/definitions/includeExcludeFilters"},"drafts":{"description":"Whether to start a run when a draft PR is created","$ref":"#/definitions/boolean"}},"additionalProperties":false}]},"trigger":{"anyOf":[{"type":"string","pattern":"^none$"},{"type":"array","items":{"$ref":"#/definitions/branchFilter"}},{"type":"object","properties":{"batch":{"description":"Whether to batch changes per branch","$ref":"#/definitions/boolean"},"branches":{"$ref":"#/definitions/includeExcludeFilters"},"paths":{"$ref":"#/definitions/includeExcludeFilters"},"tags":{"$ref":"#/definitions/includeExcludeFilters"}},"additionalProperties":false}]},"includeExcludeFilters":{"type":"object","properties":{"include":{"$ref":"#/definitions/branchFilterArray"},"exclude":{"$ref":"#/definitions/branchFilterArray"}},"additionalProperties":false},"includeExcludeStringFilters":{"anyOf":[{"type":"array","items":{"$ref":"#/definitions/nonEmptyString"}},{"type":"object","properties":{"include":{"$ref":"#/definitions/sequenceOfNonEmptyString"},"exclude":{"$ref":"#/definitions/sequenceOfNonEmptyString"}},"additionalProperties":false}]},"branchFilterArray":{"type":"array","items":{"$ref":"#/definitions/branchFilter"}},"branchFilter":{"type":"string","description":"branch name or prefix filter","pattern":"^[^\\/~\\^\\: \\[\\]\\\\]+(\\/[^\\/~\\^\\: \\[\\]\\\\]+)*$"},"templateParameters":{"anyOf":[{"type":"array","items":{"$ref":"#/definitions/templateParameter"}},{"type":"object","additionalProperties":true}]},"templateParameter":{"type":"object","properties":{"name":{"$ref":"#/definitions/nonEmptyString"},"displayName":{"description":"Human-readable name for the parameter","$ref":"#/definitions/string"},"type":{"$ref":"#/definitions/templateParameterType"},"default":{"$ref":"#/definitions/any"},"values":{"$ref":"#/definitions/sequenceOfNonEmptyString"}},"additionalProperties":false,"firstProperty":["name"]},"templateParameterType":{"anyOf":[{"type":"string","pattern":"^boolean$"},{"type":"string","pattern":"^container$"},{"type":"string","pattern":"^containerList$"},{"type":"string","pattern":"^deployment$"},{"type":"string","pattern":"^deploymentList$"},{"type":"string","pattern":"^job$"},{"type":"string","pattern":"^jobList$"},{"type":"string","pattern":"^legacyObject$"},{"type":"string","pattern":"^number$"},{"type":"string","pattern":"^object$"},{"type":"string","pattern":"^stage$"},{"type":"string","pattern":"^stageList$"},{"type":"string","pattern":"^step$"},{"type":"string","pattern":"^stepList$"},{"type":"string","pattern":"^string$"}]},"pipelineTemplateParameters":{"type":"array","items":{"$ref":"#/definitions/pipelineTemplateParameter"}},"pipelineTemplateParameter":{"type":"object","properties":{"name":{"$ref":"#/definitions/nonEmptyString"},"displayName":{"description":"Human-readable name for the parameter","$ref":"#/definitions/string"},"type":{"$ref":"#/definitions/pipelineTemplateParameterType"},"default":{"$ref":"#/definitions/any"},"values":{"$ref":"#/definitions/sequenceOfNonEmptyString"}},"additionalProperties":false,"firstProperty":["name"]},"pipelineTemplateParameterType":{"anyOf":[{"type":"string","pattern":"^boolean$"},{"type":"string","pattern":"^container$"},{"type":"string","pattern":"^containerList$"},{"type":"string","pattern":"^deployment$"},{"type":"string","pattern":"^deploymentList$"},{"type":"string","pattern":"^environment$"},{"type":"string","pattern":"^filePath$"},{"type":"string","pattern":"^job$"},{"type":"string","pattern":"^jobList$"},{"type":"string","pattern":"^number$"},{"type":"string","pattern":"^object$"},{"type":"string","pattern":"^pool$"},{"type":"string","pattern":"^secureFile$"},{"type":"string","pattern":"^serviceConnection$"},{"type":"string","pattern":"^stage$"},{"type":"string","pattern":"^stageList$"},{"type":"string","pattern":"^step$"},{"type":"string","pattern":"^stepList$"},{"type":"string","pattern":"^string$"}]},"schedules":{"type":"array","items":{"$ref":"#/definitions/schedule"}},"schedule":{"type":"object","properties":{"cron":{"$ref":"#/definitions/nonEmptyString"},"displayName":{"$ref":"#/definitions/string"},"branches":{"$ref":"#/definitions/includeExcludeFilters"},"batch":{"$ref":"#/definitions/boolean"},"always":{"$ref":"#/definitions/boolean"}},"additionalProperties":false,"firstProperty":["cron"]},"resources":{"anyOf":[{"type":"object","properties":{"builds":{"description":"List of external build resources","$ref":"#/definitions/buildResources"},"containers":{"description":"List of container images","$ref":"#/definitions/containerResources"},"pipelines":{"$ref":"#/definitions/pipelineResources"},"repositories":{"description":"List of external repositories","$ref":"#/definitions/repositoryResources"},"webhooks":{"description":"List of webhooks","$ref":"#/definitions/webhookResources"},"packages":{"description":"List of external packages","$ref":"#/definitions/packageResources"}},"additionalProperties":false},{"type":"array","items":{"$ref":"#/definitions/legacyResource"}}]},"buildResources":{"type":"array","items":{"$ref":"#/definitions/buildResource"}},"buildResource":{"type":"object","properties":{"build":{"description":"Alias or name of build artifact","$ref":"#/definitions/referenceName"},"type":{"description":"Name of the artifact type","$ref":"#/definitions/nonEmptyString"},"connection":{"description":"Name of the connection. This connection will be used for all the communication related to this artifact.","$ref":"#/definitions/nonEmptyString"},"source":{"description":"Name of the source definition/build/job","$ref":"#/definitions/nonEmptyString"},"version":{"$ref":"#/definitions/nonEmptyString"},"branch":{"$ref":"#/definitions/nonEmptyString"},"trigger":{"description":"When the artifact mentioned in this build resource completes a build, its allowed to trigger this pipeline.","$ref":"#/definitions/buildResourceTrigger"}},"additionalProperties":false,"firstProperty":["build"],"required":["build","type","connection","source"]},"buildResourceTrigger":{"anyOf":[{"type":"string","pattern":"^none$"},{"type":"string","pattern":"^true$"}]},"packageResources":{"type":"array","items":{"$ref":"#/definitions/packageResource"}},"packageResource":{"type":"object","properties":{"package":{"description":"Alias of package artifact","$ref":"#/definitions/referenceName"},"type":{"description":"Type of the package. Ex - NuGet, NPM etc.","$ref":"#/definitions/nonEmptyString"},"connection":{"description":"Name of the connection. This connection will be used for all the communication related to this artifact.","$ref":"#/definitions/nonEmptyString"},"name":{"description":"Name of the package","$ref":"#/definitions/nonEmptyString"},"version":{"$ref":"#/definitions/nonEmptyString"},"tag":{"$ref":"#/definitions/nonEmptyString"},"trigger":{"description":"Trigger a new pipeline run when a new version of this package is available.","$ref":"#/definitions/packageResourceTrigger"}},"additionalProperties":false,"firstProperty":["package"],"required":["package","type","connection","name"]},"packageResourceTrigger":{"anyOf":[{"type":"string","pattern":"^none$"},{"type":"string","pattern":"^true$"}]},"containerResources":{"type":"array","items":{"$ref":"#/definitions/containerResource"}},"containerResource":{"type":"object","properties":{"container":{"description":"ID for the container","$ref":"#/definitions/referenceName"},"type":{"$ref":"#/definitions/containerArtifactType"},"trigger":{"$ref":"#/definitions/containerResourceTrigger"},"endpoint":{"description":"ID of the service endpoint connecting to a private container registry","$ref":"#/definitions/string"},"env":{"description":"Variables to map into the container's environment","$ref":"#/definitions/mappingOfStringString"},"image":{"description":"Container image tag","$ref":"#/definitions/string","examples":["ubuntu:16.04","windows:1803"]},"mapDockerSocket":{"description":"Set this flag to false to force the agent not to setup the /var/run/docker.sock volume on container jobs","$ref":"#/definitions/boolean"},"options":{"description":"Options to pass into container host","$ref":"#/definitions/string"},"ports":{"$ref":"#/definitions/sequenceOfNonEmptyString"},"volumes":{"$ref":"#/definitions/sequenceOfNonEmptyString"},"mountReadOnly":{"$ref":"#/definitions/readOnlyMounts"}},"additionalProperties":true,"firstProperty":["container"],"required":["container","image"]},"containerArtifactType":{"anyOf":[{"type":"string","ignoreCase":"value","pattern":"^ACR$"},{"type":"string"}]},"containerResourceTrigger":{"anyOf":[{"type":"string","pattern":"^none$"},{"type":"string","pattern":"^true$"},{"type":"object","properties":{"enabled":{"$ref":"#/definitions/boolean"},"tags":{"$ref":"#/definitions/includeExcludeStringFilters"}},"additionalProperties":false}]},"pipelineResources":{"type":"array","items":{"$ref":"#/definitions/pipelineResource"}},"pipelineResource":{"type":"object","properties":{"pipeline":{"description":"ID of the pipeline resource","$ref":"#/definitions/referenceName"},"project":{"$ref":"#/definitions/nonEmptyString"},"source":{"$ref":"#/definitions/nonEmptyString"},"version":{"$ref":"#/definitions/nonEmptyString"},"branch":{"$ref":"#/definitions/nonEmptyString"},"tags":{"$ref":"#/definitions/sequenceOfNonEmptyString"},"trigger":{"$ref":"#/definitions/pipelineResourceTrigger"}},"additionalProperties":false,"firstProperty":["pipeline"],"required":["pipeline"]},"pipelineResourceTrigger":{"anyOf":[{"type":"string","pattern":"^none$"},{"type":"string","pattern":"^true$"},{"type":"object","properties":{"enabled":{"$ref":"#/definitions/boolean"},"branches":{"$ref":"#/definitions/triggerBranchFilter"},"stages":{"$ref":"#/definitions/sequenceOfNonEmptyString"},"tags":{"$ref":"#/definitions/sequenceOfNonEmptyString"}},"additionalProperties":false}]},"triggerBranchFilter":{"anyOf":[{"type":"object","properties":{"include":{"$ref":"#/definitions/branchFilterArray"},"exclude":{"$ref":"#/definitions/branchFilterArray"}},"additionalProperties":false},{"type":"array","items":{"$ref":"#/definitions/branchFilter"}}]},"repositoryResources":{"type":"array","items":{"$ref":"#/definitions/repositoryResource"}},"repositoryResource":{"type":"object","properties":{"repository":{"description":"ID of the external repository","$ref":"#/definitions/referenceName"},"endpoint":{"description":"ID of the service endpoint connecting to this repository","$ref":"#/definitions/nonEmptyString"},"trigger":{"$ref":"#/definitions/trigger"},"checkoutOptions":{"deprecationMessage":"This location is deprecated, `checkoutOptions` should be a peer of the `repository` keyword.","doNotSuggest":true,"$ref":"#/definitions/repositoryCheckoutOptions"}},"additionalProperties":true,"firstProperty":["repository"],"required":["repository"]},"repositoryCheckoutOptions":{"type":"object","properties":{"clean":{"description":"Scorch the repo before fetching?","enum":["true","false"],"$ref":"#/definitions/string"},"fetchDepth":{"description":"Depth of Git graph to fetch","$ref":"#/definitions/string"},"lfs":{"description":"Fetch and checkout Git LFS objects?","$ref":"#/definitions/string"},"submodules":{"description":"Fetch and checkout submodules?","$ref":"#/definitions/string"},"persistCredentials":{"description":"Keep credentials available for later use?","$ref":"#/definitions/string"}},"additionalProperties":false},"legacyResource":{"type":"object","properties":{"repo":{"$ref":"#/definitions/legacyRepoResourceAlias"},"clean":{"description":"Scorch the repo before fetching?","enum":["true","false"],"$ref":"#/definitions/string"},"fetchDepth":{"description":"Depth of Git graph to fetch","$ref":"#/definitions/string"},"lfs":{"description":"Fetch and checkout Git LFS objects?","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["repo"]},"legacyRepoResourceAlias":{"type":"string","pattern":"^self$"},"webhookResources":{"type":"array","items":{"$ref":"#/definitions/webhookResource"}},"webhookResource":{"type":"object","properties":{"webhook":{"description":"Name of the webhook","$ref":"#/definitions/referenceName"},"connection":{"description":"Name of the connection. In case of offline webhook this will be the type of Incoming Webhook otherwise it will be the type of the webhook extension.","$ref":"#/definitions/nonEmptyString"},"type":{"description":"Name of the webhook extension. leave this empty if its offline webhook.","$ref":"#/definitions/nonEmptyString"},"filters":{"description":"List of trigger filters.","$ref":"#/definitions/webhookFilters"}},"additionalProperties":false,"firstProperty":["webhook"],"required":["webhook","connection"]},"webhookFilters":{"type":"array","items":{"$ref":"#/definitions/webhookFilter"}},"webhookFilter":{"type":"object","properties":{"path":{"description":"json path to select data from event payload","$ref":"#/definitions/nonEmptyString"},"value":{"description":"Expected value for the filter to match","$ref":"#/definitions/nonEmptyString"}},"additionalProperties":false,"firstProperty":["path"],"required":["path","value"]},"variablesTemplate":{"type":"object","properties":{"parameters":{"$ref":"#/definitions/templateParameters"},"variables":{"$ref":"#/definitions/variables"}},"additionalProperties":false},"variables":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"array","items":{"$ref":"#/definitions/variable"}}]},"variable":{"anyOf":[{"type":"object","properties":{"name":{"$ref":"#/definitions/nonEmptyString"},"value":{"$ref":"#/definitions/string"},"readonly":{"$ref":"#/definitions/boolean"}},"additionalProperties":false,"firstProperty":["name"]},{"type":"object","properties":{"group":{"$ref":"#/definitions/nonEmptyString"}},"additionalProperties":false,"firstProperty":["group"]},{"type":"object","properties":{"template":{"$ref":"#/definitions/nonEmptyString"},"parameters":{"$ref":"#/definitions/mapping"}},"additionalProperties":false,"firstProperty":["template"]}]},"stagesTemplate":{"type":"object","properties":{"parameters":{"$ref":"#/definitions/templateParameters"},"stages":{"$ref":"#/definitions/stages"}},"additionalProperties":false},"stages":{"type":"array","items":{"$ref":"#/definitions/stage"}},"stage":{"anyOf":[{"type":"object","properties":{"stage":{"description":"ID of the stage","$ref":"#/definitions/string"},"displayName":{"description":"Human-readable name for the stage","$ref":"#/definitions/string"},"pool":{"description":"Pool where jobs in this stage will run unless otherwise specified","$ref":"#/definitions/pool"},"dependsOn":{"description":"Any stages which must complete before this one","$ref":"#/definitions/jobDependsOn"},"condition":{"description":"Evaluate this condition expression to determine whether to run this stage","$ref":"#/definitions/string"},"variables":{"description":"Stage-specific variables","$ref":"#/definitions/variables"},"jobs":{"description":"Jobs which make up the stage","$ref":"#/definitions/jobs"},"lockBehavior":{"description":"Behavior lock requests from this stage should exhibit in relation to other exclusive lock requests","$ref":"#/definitions/lockBehavior"}},"additionalProperties":false,"firstProperty":["stage"]},{"type":"object","properties":{"template":{"description":"Reference to a template for this stage","$ref":"#/definitions/nonEmptyString"},"parameters":{"description":"Parameters used in a stage template","$ref":"#/definitions/mapping"}},"additionalProperties":false,"firstProperty":["template"]}]},"lockBehavior":{"anyOf":[{"type":"string","pattern":"^sequential$"},{"type":"string","pattern":"^runLatest$"}]},"extendsParameters":{"type":"array","items":{"$ref":"#/definitions/templateParameter"}},"extendsTemplate":{"anyOf":[{"type":"object","properties":{"stages":{"$ref":"#/definitions/stages"},"trigger":{"$ref":"#/definitions/trigger"},"resources":{"$ref":"#/definitions/resources"},"parameters":{"$ref":"#/definitions/extendsParameters"},"variables":{"$ref":"#/definitions/variables"}},"additionalProperties":false},{"type":"object","properties":{"jobs":{"$ref":"#/definitions/jobs"},"trigger":{"$ref":"#/definitions/trigger"},"resources":{"$ref":"#/definitions/resources"},"parameters":{"$ref":"#/definitions/extendsParameters"},"variables":{"$ref":"#/definitions/variables"}},"additionalProperties":false},{"type":"object","properties":{"steps":{"$ref":"#/definitions/steps"},"trigger":{"$ref":"#/definitions/trigger"},"resources":{"$ref":"#/definitions/resources"},"parameters":{"$ref":"#/definitions/extendsParameters"},"variables":{"$ref":"#/definitions/variables"}},"additionalProperties":false},{"type":"object","properties":{"trigger":{"$ref":"#/definitions/trigger"},"resources":{"$ref":"#/definitions/resources"},"parameters":{"$ref":"#/definitions/extendsParameters"},"extends":{"$ref":"#/definitions/extends"}},"additionalProperties":false}]},"extendsTemplateBase":{"type":"object","properties":{"trigger":{"$ref":"#/definitions/trigger"},"resources":{"$ref":"#/definitions/resources"},"parameters":{"$ref":"#/definitions/extendsParameters"},"variables":{"$ref":"#/definitions/variables"}},"additionalProperties":false},"parametersTemplate":{"anyOf":[{"type":"object","properties":{"parameters":{"description":"Step-specific parameters","$ref":"#/definitions/templateParameters"},"steps":{"description":"A list of steps to run","$ref":"#/definitions/steps"}},"additionalProperties":false,"required":["steps"]},{"type":"object","properties":{"parameters":{"description":"Parameters used in a job template","$ref":"#/definitions/templateParameters"},"jobs":{"description":"Jobs which make up the pipeline","$ref":"#/definitions/jobs"}},"additionalProperties":false},{"type":"object","properties":{"parameters":{"$ref":"#/definitions/templateParameters"},"stages":{"$ref":"#/definitions/stages"}},"additionalProperties":false},{"type":"object","properties":{"resources":{"$ref":"#/definitions/resources"},"parameters":{"$ref":"#/definitions/templateParameters"},"extends":{"description":"Extends a template","$ref":"#/definitions/extends"}},"additionalProperties":false,"required":["extends"]}]},"extends":{"type":"object","properties":{"template":{"$ref":"#/definitions/nonEmptyString"},"parameters":{"description":"Parameters used in the extend","$ref":"#/definitions/mapping"}},"additionalProperties":false},"jobsTemplate":{"anyOf":[{"type":"object","properties":{"parameters":{"description":"Parameters used in a job template","$ref":"#/definitions/templateParameters"},"jobs":{"description":"Jobs which make up the pipeline","$ref":"#/definitions/jobs"}},"additionalProperties":false},{"type":"object","properties":{"parameters":{"description":"Parameters used in a phase template","$ref":"#/definitions/templateParameters"},"phases":{"description":"Phases which make up the pipeline","deprecationMessage":"This option is deprecated, use `jobs` instead","doNotSuggest":true,"$ref":"#/definitions/phases"}},"additionalProperties":false}]},"jobs":{"type":"array","items":{"$ref":"#/definitions/job"}},"job":{"anyOf":[{"type":"object","properties":{"job":{"description":"ID of the job","$ref":"#/definitions/referenceName"},"displayName":{"description":"Human-readable name for the job","$ref":"#/definitions/string"},"dependsOn":{"description":"Any jobs which must complete before this one","$ref":"#/definitions/jobDependsOn"},"condition":{"description":"Evaluate this condition expression to determine whether to run this job","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/jobContinueOnError"},"timeoutInMinutes":{"description":"Time to wait for this job to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"cancelTimeoutInMinutes":{"description":"Time to wait for the job to cancel before forcibly terminating it","$ref":"#/definitions/nonEmptyString"},"variables":{"description":"Job-specific variables","$ref":"#/definitions/variables"},"strategy":{"description":"Execution strategy for this job","$ref":"#/definitions/jobStrategy"},"pool":{"description":"Pool where this job will run","$ref":"#/definitions/pool"},"container":{"description":"Container resource name","$ref":"#/definitions/jobContainer"},"services":{"$ref":"#/definitions/jobServices"},"workspace":{"$ref":"#/definitions/jobWorkspace"},"uses":{"description":"Any resources required by this job that are not already referenced","$ref":"#/definitions/explicitResources"},"steps":{"description":"A list of steps to run","$ref":"#/definitions/steps"}},"additionalProperties":false,"firstProperty":["job"]},{"type":"object","properties":{"deployment":{"$ref":"#/definitions/string"},"displayName":{"description":"Human-readable name for the deployment","$ref":"#/definitions/string"},"dependsOn":{"description":"Any jobs which must complete before this one","$ref":"#/definitions/jobDependsOn"},"condition":{"description":"Evaluate this condition expression to determine whether to run this deployment","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/jobContinueOnError"},"timeoutInMinutes":{"description":"Time to wait for this job to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"cancelTimeoutInMinutes":{"description":"Time to wait for the job to cancel before forcibly terminating it","$ref":"#/definitions/nonEmptyString"},"variables":{"description":"Deployment-specific variables","$ref":"#/definitions/variables"},"pool":{"description":"Pool where this job will run","$ref":"#/definitions/pool"},"environment":{"$ref":"#/definitions/deploymentEnvironment"},"strategy":{"description":"Execution strategy for this deployment","$ref":"#/definitions/deploymentStrategy"},"workspace":{"description":"What to clean up before the job runs","$ref":"#/definitions/jobWorkspace"},"uses":{"description":"Any resources required by this job that are not already referenced","$ref":"#/definitions/explicitResources"},"container":{"description":"Container resource name","$ref":"#/definitions/jobContainer"},"services":{"description":"Container resources to run as a service container","$ref":"#/definitions/jobServices"}},"additionalProperties":false,"firstProperty":["deployment"]},{"type":"object","properties":{"template":{"description":"Reference to a template for this deployment","$ref":"#/definitions/nonEmptyString"},"parameters":{"description":"Parameters used in a deployment template","$ref":"#/definitions/mapping"}},"additionalProperties":false,"firstProperty":["template"]}]},"explicitResources":{"type":"object","properties":{"repositories":{"description":"Repository references","$ref":"#/definitions/sequenceOfNonEmptyString"},"pools":{"description":"Pool references","$ref":"#/definitions/sequenceOfNonEmptyString"}},"additionalProperties":false},"pool":{"description":"Pool details","anyOf":[{"type":"string"},{"type":"object","properties":{"name":{"description":"Name of a pool","$ref":"#/definitions/nonEmptyString"},"demands":{"description":"List of demands (for a private pool)","$ref":"#/definitions/poolDemands"}},"additionalProperties":true}]},"poolDemands":{"anyOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/definitions/nonEmptyString"}}]},"jobContainer":{"anyOf":[{"type":"string"},{"type":"object","properties":{"alias":{"description":"The alias of the container resource","$ref":"#/definitions/string"}},"additionalProperties":false},{"type":"object","properties":{"endpoint":{"description":"ID of the service endpoint connecting to a private container registry","$ref":"#/definitions/string"},"env":{"description":"Variables to map into the container's environment","$ref":"#/definitions/mappingOfStringString"},"image":{"description":"Container image tag","$ref":"#/definitions/string","examples":["ubuntu:16.04","windows:1803"]},"mapDockerSocket":{"description":"Set this flag to false to force the agent not to setup the /var/run/docker.sock volume on container jobs","$ref":"#/definitions/boolean"},"options":{"description":"Options to pass into container host","$ref":"#/definitions/string"},"ports":{"$ref":"#/definitions/sequenceOfNonEmptyString"},"volumes":{"$ref":"#/definitions/sequenceOfNonEmptyString"},"mountReadOnly":{"$ref":"#/definitions/readOnlyMounts"}},"required":["image"]}]},"containerBase":{"type":"object","properties":{"endpoint":{"description":"ID of the service endpoint connecting to a private container registry","$ref":"#/definitions/string"},"env":{"description":"Variables to map into the container's environment","$ref":"#/definitions/mappingOfStringString"},"image":{"description":"Container image tag","$ref":"#/definitions/string","examples":["ubuntu:16.04","windows:1803"]},"mapDockerSocket":{"description":"Set this flag to false to force the agent not to setup the /var/run/docker.sock volume on container jobs","$ref":"#/definitions/boolean"},"options":{"description":"Options to pass into container host","$ref":"#/definitions/string"},"ports":{"$ref":"#/definitions/sequenceOfNonEmptyString"},"volumes":{"$ref":"#/definitions/sequenceOfNonEmptyString"},"mountReadOnly":{"$ref":"#/definitions/readOnlyMounts"}},"additionalProperties":false,"required":["image"]},"readOnlyMounts":{"type":"object","properties":{"work":{"description":"Mount the work directory as readonly","$ref":"#/definitions/boolean"},"externals":{"description":"Mount the externals directory as readonly","$ref":"#/definitions/boolean"},"tools":{"description":"Mount the tools directory as readonly","$ref":"#/definitions/boolean"},"tasks":{"description":"Mount the tasks directory as readonly","$ref":"#/definitions/boolean"}},"additionalProperties":false},"jobServices":{"type":"object","additionalProperties":true},"jobWorkspace":{"type":"object","properties":{"clean":{"description":"Which parts of the workspace should be scorched before fetching","enum":["outputs","resources","all"],"$ref":"#/definitions/string"}},"additionalProperties":false},"jobStrategy":{"anyOf":[{"type":"object","properties":{"matrix":{"$ref":"#/definitions/jobMatrix"},"maxParallel":{"description":"Maximum number of jobs running in parallel","$ref":"#/definitions/nonEmptyString"}},"additionalProperties":false},{"type":"object","properties":{"parallel":{"description":"Run the job this many times","$ref":"#/definitions/nonEmptyString"}},"additionalProperties":false}]},"jobMatrix":{"anyOf":[{"type":"object","additionalProperties":true,"minProperties":1,"patternProperties":{"^[A-Za-z0-9_]+$":{"$ref":"#/definitions/matrixProperties"}}},{"type":"string"}]},"matrixProperties":{"type":"object","description":"Variable-value pair to pass in this matrix instance","additionalProperties":true},"deploymentEnvironment":{"description":"Environment details","anyOf":[{"type":"string"},{"type":"object","properties":{"name":{"description":"Name of environment","$ref":"#/definitions/nonEmptyString"},"resourceName":{"description":"Name of resource","$ref":"#/definitions/nonEmptyString"},"resourceId":{"description":"Id of resource","$ref":"#/definitions/nonEmptyString"},"resourceType":{"description":"Type of environment resource","$ref":"#/definitions/nonEmptyString"},"tags":{"description":"List of tag filters","$ref":"#/definitions/nonEmptyString"}},"additionalProperties":false}]},"deploymentStrategy":{"anyOf":[{"type":"object","properties":{"runOnce":{"description":"RunOnce Deployment strategy","$ref":"#/definitions/runOnceDeploymentStrategy"}},"additionalProperties":false},{"type":"object","properties":{"rolling":{"description":"Rolling Deployment strategy","$ref":"#/definitions/rollingDeploymentStrategy"}},"additionalProperties":false},{"type":"object","properties":{"canary":{"description":"Canary Deployment strategy","$ref":"#/definitions/canaryDeploymentStrategy"}},"additionalProperties":false}]},"preDeployHook":{"type":"object","properties":{"steps":{"description":"A list of steps to run","$ref":"#/definitions/steps"},"pool":{"description":"Pool where pre deploy steps will run","$ref":"#/definitions/pool"}},"additionalProperties":false},"deployHook":{"type":"object","properties":{"steps":{"description":"A list of steps to run","$ref":"#/definitions/steps"},"pool":{"description":"Pool where deploy steps will run","$ref":"#/definitions/pool"}},"additionalProperties":false},"routeTrafficHook":{"type":"object","properties":{"steps":{"description":"A list of steps to run","$ref":"#/definitions/steps"},"pool":{"description":"Pool where route traffic steps will run","$ref":"#/definitions/pool"}},"additionalProperties":false},"postRouteTrafficHook":{"type":"object","properties":{"steps":{"description":"A list of steps to run","$ref":"#/definitions/steps"},"pool":{"description":"Pool where post route traffic steps will run","$ref":"#/definitions/pool"}},"additionalProperties":false},"onSuccessOrFailureHook":{"type":"object","properties":{"failure":{"description":"Runs on failure of any step","$ref":"#/definitions/onFailureHook"},"success":{"description":"Runs on success of all of the steps","$ref":"#/definitions/onSuccessHook"}},"additionalProperties":false},"onFailureHook":{"type":"object","properties":{"steps":{"description":"A list of steps to run","$ref":"#/definitions/steps"},"pool":{"description":"Pool where post on failure steps will run","$ref":"#/definitions/pool"}},"additionalProperties":false},"onSuccessHook":{"type":"object","properties":{"steps":{"description":"A list of steps to run","$ref":"#/definitions/steps"},"pool":{"description":"Pool where on success steps will run","$ref":"#/definitions/pool"}},"additionalProperties":false},"runOnceDeploymentStrategy":{"type":"object","properties":{"preDeploy":{"description":"Pre deploy hook for runOnce deployment strategy","$ref":"#/definitions/preDeployHook"},"deploy":{"description":"Deploy hook for runOnce deployment strategy","$ref":"#/definitions/deployHook"},"routeTraffic":{"description":"Route traffic hook for runOnce deployment strategy","$ref":"#/definitions/routeTrafficHook"},"postRouteTraffic":{"description":"Post route traffic hook for runOnce deployment strategy","$ref":"#/definitions/postRouteTrafficHook"},"on":{"description":"On success or failure hook for runOnce deployment strategy","$ref":"#/definitions/onSuccessOrFailureHook"}},"additionalProperties":false},"rollingDeploymentStrategy":{"type":"object","properties":{"maxParallel":{"description":"Maximum number of jobs running in parallel","$ref":"#/definitions/nonEmptyString"},"preDeploy":{"description":"Pre deploy hook for rolling deployment strategy","$ref":"#/definitions/preDeployHook"},"deploy":{"description":"Deploy hook for rolling deployment strategy","$ref":"#/definitions/deployHook"},"routeTraffic":{"description":"Route traffic hook for rolling deployment strategy","$ref":"#/definitions/routeTrafficHook"},"postRouteTraffic":{"description":"Post route traffic hook for rolling deployment strategy","$ref":"#/definitions/postRouteTrafficHook"},"on":{"description":"On success or failure hook for rolling deployment strategy","$ref":"#/definitions/onSuccessOrFailureHook"}},"additionalProperties":false},"canaryDeploymentStrategy":{"type":"object","properties":{"increments":{"description":"Maximum batch size for deployment","$ref":"#/definitions/canaryDeploymentIncrements"},"preDeploy":{"description":"Pre deploy hook for canary deployment strategy","$ref":"#/definitions/preDeployHook"},"deploy":{"description":"Deploy hook for canary deployment strategy","$ref":"#/definitions/deployHook"},"routeTraffic":{"description":"Route traffic hook for canary deployment strategy","$ref":"#/definitions/routeTrafficHook"},"postRouteTraffic":{"description":"Post route traffic hook for canary deployment strategy","$ref":"#/definitions/postRouteTrafficHook"},"on":{"description":"On success or failure hook for canary deployment strategy","$ref":"#/definitions/onSuccessOrFailureHook"}},"additionalProperties":false},"canaryDeploymentIncrements":{"type":"array","items":{"$ref":"#/definitions/nonEmptyString"}},"phases":{"type":"array","deprecationMessage":"This option is deprecated, use `jobs` instead","items":{"$ref":"#/definitions/phase"}},"phase":{"deprecationMessage":"This option is deprecated, use `job` (inside `jobs`) instead","anyOf":[{"type":"object","properties":{"phase":{"description":"ID of the phase","$ref":"#/definitions/referenceName"},"dependsOn":{"description":"Any phases which must complete before this one","$ref":"#/definitions/jobDependsOn"},"displayName":{"description":"Human-readable name of the phase","$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this phase","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/jobContinueOnError"},"queue":{"description":"Queue where this phase will run","deprecationMessage":"This option is deprecated, use pool instead","doNotSuggest":true,"$ref":"#/definitions/phaseQueueTarget"},"variables":{"description":"Phase-specific variables","$ref":"#/definitions/variables"},"steps":{"description":"A list of steps to run in this phase","$ref":"#/definitions/steps"}},"additionalProperties":false,"firstProperty":["phase"]},{"type":"object","properties":{"phase":{"description":"ID of the phase","$ref":"#/definitions/referenceName"},"dependsOn":{"description":"Any phases which must complete before this one","$ref":"#/definitions/jobDependsOn"},"displayName":{"description":"Human-readable name of the phase","$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this phase","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/jobContinueOnError"},"server":{"description":"True if this is an agent-less phase (runs on server)","deprecationMessage":"This option is deprecated, use pool:server instead","doNotSuggest":true,"$ref":"#/definitions/phaseServerTarget"},"variables":{"description":"Phase-specific variables","$ref":"#/definitions/variables"},"steps":{"description":"A list of steps to run in this phase","$ref":"#/definitions/steps"}},"additionalProperties":false,"firstProperty":["phase"]},{"type":"object","properties":{"template":{"description":"Reference to a template for this phase","$ref":"#/definitions/nonEmptyString"},"parameters":{"description":"Parameters used in a phase template","$ref":"#/definitions/mapping"}},"additionalProperties":false,"firstProperty":["template"]}]},"phaseQueueTarget":{"description":"Queue details","deprecationMessage":"This option is deprecated, use `pool` under `jobs` instead","anyOf":[{"type":"string"},{"type":"object","properties":{"cancelTimeoutInMinutes":{"description":"Time to wait for the phase to cancel before forcibly terminating it","$ref":"#/definitions/nonEmptyString"},"container":{"description":"Container resource name","$ref":"#/definitions/nonEmptyString"},"demands":{"description":"List of demands (for a private queue)","$ref":"#/definitions/phaseTargetDemands"},"matrix":{"$ref":"#/definitions/phaseTargetMatrix"},"name":{"description":"Name of a queue","$ref":"#/definitions/string"},"parallel":{"description":"Maximum number of parallel agent executions","$ref":"#/definitions/nonEmptyString"},"timeoutInMinutes":{"description":"Time to wait before cancelling the phase","$ref":"#/definitions/nonEmptyString"},"workspace":{"$ref":"#/definitions/phaseTargetWorkspace"}},"additionalProperties":false}]},"phaseServerTarget":{"anyOf":[{"type":"string"},{"type":"object","properties":{"cancelTimeoutInMinutes":{"description":"Time to wait for the job to cancel before forcibly terminating it","$ref":"#/definitions/nonEmptyString"},"matrix":{"$ref":"#/definitions/phaseTargetMatrix"},"parallel":{"description":"Maximum number of parallel agent executions","$ref":"#/definitions/nonEmptyString"},"timeoutInMinutes":{"description":"Time to wait before cancelling the job","$ref":"#/definitions/nonEmptyString"}},"additionalProperties":false}]},"phaseTargetDemands":{"anyOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/definitions/nonEmptyString"}}]},"phaseTargetWorkspace":{"type":"object","properties":{"clean":{"description":"Scorch the repo before fetching?","enum":["outputs","resources","all"],"$ref":"#/definitions/string"}},"additionalProperties":false},"phaseTargetMatrix":{"description":"List of permutations of variable values to run","anyOf":[{"type":"object","additionalProperties":true},{"type":"string"}],"minProperties":1,"patternProperties":{"^[A-Za-z0-9_]+$":{"$ref":"#/definitions/matrixProperties"}}},"stepsTemplate":{"type":"object","properties":{"parameters":{"description":"Step-specific parameters","$ref":"#/definitions/templateParameters"},"steps":{"description":"A list of steps to run","$ref":"#/definitions/steps"}},"additionalProperties":false},"steps":{"type":"array","items":{"$ref":"#/definitions/step"}},"step":{"anyOf":[{"type":"object","$ref":"#/definitions/task"},{"type":"object","properties":{"script":{"description":"An inline script","$ref":"#/definitions/string"},"failOnStderr":{"description":"Fail the task if output is sent to Stderr?","$ref":"#/definitions/string"},"workingDirectory":{"description":"Start the script with this working directory","$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["script"],"required":["script"]},{"type":"object","properties":{"powershell":{"description":"Inline PowerShell or reference to a PowerShell file","$ref":"#/definitions/string"},"errorActionPreference":{"$ref":"#/definitions/string"},"failOnStderr":{"description":"Fail the task if output is sent to Stderr?","$ref":"#/definitions/string"},"ignoreLASTEXITCODE":{"description":"Check the final exit code of the script to determine whether the step succeeded?","$ref":"#/definitions/string"},"workingDirectory":{"description":"Start the script with this working directory","$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["powershell"],"required":["powershell"]},{"type":"object","properties":{"pwsh":{"description":"Inline PowerShell or reference to a PowerShell file","$ref":"#/definitions/string"},"errorActionPreference":{"$ref":"#/definitions/string"},"failOnStderr":{"description":"Fail the task if output is sent to Stderr?","$ref":"#/definitions/string"},"ignoreLASTEXITCODE":{"description":"Check the final exit code of the script to determine whether the step succeeded?","$ref":"#/definitions/string"},"workingDirectory":{"description":"Start the script with this working directory","$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["pwsh"],"required":["pwsh"]},{"type":"object","properties":{"bash":{"description":"An inline script","$ref":"#/definitions/string"},"failOnStderr":{"description":"Fail the task if output is sent to Stderr?","$ref":"#/definitions/string"},"workingDirectory":{"description":"Start the script with this working directory","$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["bash"],"required":["bash"]},{"type":"object","properties":{"checkout":{"description":"Alias of the repository resource to check out or 'none'","$ref":"#/definitions/string"},"clean":{"description":"Scorch the repo before fetching?","enum":["true","false"],"$ref":"#/definitions/string"},"fetchDepth":{"description":"Depth of Git graph to fetch","$ref":"#/definitions/string"},"lfs":{"description":"Fetch Git-LFS objects?","$ref":"#/definitions/string"},"persistCredentials":{"description":"Keep credentials available for later use?","$ref":"#/definitions/string"},"submodules":{"description":"Check out Git submodules?","$ref":"#/definitions/string"},"path":{"description":"Path of the repository to check out","$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["checkout"]},{"type":"object","properties":{"download":{"description":"Reference to the pipeline","$ref":"#/definitions/nonEmptyString"},"artifact":{"description":"Name of the artifact to download","$ref":"#/definitions/nonEmptyString"},"patterns":{"description":"Pattern to download files from artifact","$ref":"#/definitions/nonEmptyString"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["download"],"required":["download"]},{"type":"object","properties":{"downloadBuild":{"description":"ID for the build resource","$ref":"#/definitions/nonEmptyString"},"artifact":{"description":"Name of the artifact to download","$ref":"#/definitions/string"},"path":{"description":"Path to download the artifact into","$ref":"#/definitions/string"},"patterns":{"description":"Downloads the files which matches the patterns","$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["downloadBuild"]},{"type":"object","properties":{"getPackage":{"description":"ID for the package resource","$ref":"#/definitions/nonEmptyString"},"path":{"description":"Path to download the package into","$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["getPackage"]},{"type":"object","properties":{"upload":{"deprecationMessage":"This option is deprecated, use `publish` instead","doNotSuggest":true,"$ref":"#/definitions/string"},"artifact":{"$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["upload"]},{"type":"object","properties":{"publish":{"$ref":"#/definitions/string"},"artifact":{"$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["publish"]},{"type":"object","properties":{"template":{"description":"Reference to a template for this step","$ref":"#/definitions/nonEmptyString"},"parameters":{"description":"Parameters used in a step template","$ref":"#/definitions/mapping"}},"additionalProperties":false,"firstProperty":["template"]},{"type":"object","properties":{"restoreCache":{"description":"The name of the key","$ref":"#/definitions/nonEmptyString"},"path":{"description":"The folder path to download the cache to. This can be a fully-qualified path or a path relative to the root of the repository. Wildcards are not supported.","$ref":"#/definitions/nonEmptyString"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["restoreCache"],"required":["restoreCache","path"]},{"type":"object","properties":{"saveCache":{"description":"The name of the key","$ref":"#/definitions/nonEmptyString"},"path":{"description":"The folder or file path to publish. This can be a fully-qualified path or a path relative to the root of the repository. Wildcards are not supported.","$ref":"#/definitions/nonEmptyString"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["saveCache"],"required":["saveCache","path"]},{"type":"object","properties":{"reviewApp":{"$ref":"#/definitions/string"},"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false,"firstProperty":["reviewApp"]}]},"stepTarget":{"description":"Step target","anyOf":[{"type":"string"},{"type":"object","properties":{"container":{"description":"Container to target (or 'host' for host machine)","$ref":"#/definitions/nonEmptyString"},"commands":{"description":"Set of allowed logging commands ('any' or 'restricted')","enum":["any","restricted"],"$ref":"#/definitions/string"},"settableVariables":{"description":"Restrictions on which variables that can be set","$ref":"#/definitions/variableRestrictions"}},"additionalProperties":false}]},"variableRestrictions":{"anyOf":[{"type":"string","ignoreCase":"value","pattern":"^none$"},{"type":"array","items":{"$ref":"#/definitions/nonEmptyString"}}]},"jobDecoratorSteps":{"type":"object","properties":{"steps":{"description":"A list of steps to run in this job","$ref":"#/definitions/tasks"}},"additionalProperties":false},"tasks":{"type":"array","items":{"$ref":"#/definitions/task"}},"taskBase":{"type":"object","properties":{"condition":{"description":"Evaluate this condition expression to determine whether to run this task","$ref":"#/definitions/string"},"continueOnError":{"description":"Continue running even on failure?","$ref":"#/definitions/boolean"},"displayName":{"description":"Human-readable name for the task","$ref":"#/definitions/string"},"target":{"description":"Environment in which to run this task","$ref":"#/definitions/stepTarget"},"enabled":{"description":"Run this task when the job runs?","$ref":"#/definitions/boolean"},"env":{"description":"Variables to map into the process's environment","$ref":"#/definitions/mappingOfStringString"},"name":{"description":"ID of the step","$ref":"#/definitions/referenceName"},"timeoutInMinutes":{"description":"Time to wait for this task to complete before the server kills it","$ref":"#/definitions/nonEmptyString"},"retryCountOnTaskFailure":{"description":"Number of retries if the task fails","$ref":"#/definitions/string"}},"additionalProperties":false},"jobContinueOnError":{"type":"string"},"jobDependsOn":{"anyOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/definitions/string"}}]},"referenceName":{"type":"string","pattern":"^[-_A-Za-z0-9]*$"},"boolean":{"anyOf":[{"type":"string","ignoreCase":"value","pattern":"^true$"},{"type":"string","ignoreCase":"value","pattern":"^y$"},{"type":"string","ignoreCase":"value","pattern":"^yes$"},{"type":"string","ignoreCase":"value","pattern":"^on$"},{"type":"string","ignoreCase":"value","pattern":"^false$"},{"type":"string","ignoreCase":"value","pattern":"^n$"},{"type":"string","ignoreCase":"value","pattern":"^no$"},{"type":"string","ignoreCase":"value","pattern":"^off$"}]},"string_allowExpressions":{"type":"string"},"nonEmptyString":{"type":"string"},"sequenceOfNonEmptyString":{"type":"array","items":{"$ref":"#/definitions/nonEmptyString"}},"mappingOfStringString":{"type":"object","additionalProperties":true},"any_allowExpressions":{"anyOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/definitions/any"}},{"type":"object","additionalProperties":true}]},"task":{"type":"object","properties":{"task":{"anyOf":[{"description":"A variant of the Codesign Validation build task that auto-runs on Production builds.","doNotSuggest":false,"ignoreCase":"value","enum":["CodeSignValidationInjected@1"]},{"description":"Run a PowerShell script on Linux, macOS, or Windows","doNotSuggest":false,"ignoreCase":"value","enum":["PowerShell@2"]},{"description":"Run a PowerShell script","doNotSuggest":false,"ignoreCase":"value","enum":["PowerShell@1"]},{"description":"Run a PowerShell script within an Azure environment","doNotSuggest":false,"ignoreCase":"value","enum":["AzurePowerShell@5"]},{"description":"Run a PowerShell script within an Azure environment","doNotSuggest":false,"ignoreCase":"value","enum":["AzurePowerShell@2"]},{"description":"Run a PowerShell script within an Azure environment","doNotSuggest":false,"ignoreCase":"value","enum":["AzurePowerShell@3"]},{"description":"Run a PowerShell script within an Azure environment","doNotSuggest":false,"ignoreCase":"value","enum":["AzurePowerShell@4"]},{"description":"Run a PowerShell script within an Azure environment","doNotSuggest":false,"ignoreCase":"value","enum":["AzurePowerShell@1"]},{"description":"Run scripts and make changes to a MySQL Database","doNotSuggest":false,"ignoreCase":"value","enum":["MysqlDeploymentOnMachineGroup@1"]},{"description":"Installs and configures the MicroBuild Prefast plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildPrefastPlugin@2"]},{"description":"Authentication task for the pip client used for installing Python distributions","doNotSuggest":false,"ignoreCase":"value","enum":["PipAuthenticate@1"]},{"description":"Authentication task for the pip client used for installing Python distributions","doNotSuggest":false,"ignoreCase":"value","enum":["PipAuthenticate@0"]},{"description":"Build, test, and deploy with Apache Maven","doNotSuggest":false,"ignoreCase":"value","enum":["Maven@2"]},{"description":"Build, test, and deploy with Apache Maven","doNotSuggest":false,"ignoreCase":"value","enum":["Maven@3"]},{"description":"Build with Apache Maven","doNotSuggest":false,"ignoreCase":"value","enum":["Maven@1"]},{"description":"Zip Files and Folder","doNotSuggest":false,"ignoreCase":"value","enum":["zip@0"]},{"description":"Publish Symbols to Artifact Services - Internal Preview","doNotSuggest":false,"ignoreCase":"value","enum":["artifactSymbolTask@0"]},{"description":"Run a powershell script to rollback deployments. Task execution context is available in the powershell context for implementing conditional rollback","doNotSuggest":false,"ignoreCase":"value","enum":["Rollback@1"]},{"description":"Build, test, package, or publish a dotnet application, or run a custom dotnet command","doNotSuggest":false,"ignoreCase":"value","enum":["DotNetCoreCLI@2"]},{"description":"Build, test and publish using dotnet core command-line.","deprecationMessage":"DotNetCoreCLI is deprecated - Build, test and publish using dotnet core command-line.","doNotSuggest":true,"ignoreCase":"value","enum":["DotNetCoreCLI@0"]},{"description":"Build, test and publish using dotnet core command-line.","doNotSuggest":false,"ignoreCase":"value","enum":["DotNetCoreCLI@1"]},{"description":"Tokenizes a file.","doNotSuggest":false,"ignoreCase":"value","enum":["JSONTokenizer@1"]},{"description":"Send start job telemetry for .NET Core builds","doNotSuggest":false,"ignoreCase":"value","enum":["SendStartTelemetry@0"]},{"description":"This task is deprecated. Use 'NuGet' instead.","deprecationMessage":"XamarinComponentRestore is deprecated - This task is deprecated. Use 'NuGet' instead.","doNotSuggest":true,"ignoreCase":"value","enum":["XamarinComponentRestore@0"]},{"description":"ReportGenerator converts coverage reports generated by coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover, gcov or lcov into human readable reports in various formats.","doNotSuggest":false,"ignoreCase":"value","enum":["reportgenerator@5"]},{"description":"ReportGenerator converts coverage reports generated by coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover, gcov or lcov into human readable reports in various formats.","doNotSuggest":false,"ignoreCase":"value","enum":["reportgenerator@4"]},{"description":"Update Azure App Service using Web Deploy / Kudu REST APIs","doNotSuggest":false,"ignoreCase":"value","enum":["AzureRmWebAppDeployment@2"]},{"description":"Deploy to Azure App Service a web, mobile, or API app using Docker, Java, .NET, .NET Core, Node.js, PHP, Python, or Ruby","doNotSuggest":false,"ignoreCase":"value","enum":["AzureRmWebAppDeployment@3"]},{"description":"Deploy to Azure App Service a web, mobile, or API app using Docker, Java, .NET, .NET Core, Node.js, PHP, Python, or Ruby","doNotSuggest":false,"ignoreCase":"value","enum":["AzureRmWebAppDeployment@4"]},{"description":"Execute PowerShell scripts on remote machine(s)","doNotSuggest":false,"ignoreCase":"value","enum":["PowerShellOnTargetMachines@1"]},{"description":"Execute PowerShell scripts on remote machines using PSSession and Invoke-Command for remoting","doNotSuggest":false,"ignoreCase":"value","enum":["PowerShellOnTargetMachines@3"]},{"description":"Execute PowerShell scripts on remote machine(s)","doNotSuggest":false,"ignoreCase":"value","enum":["PowerShellOnTargetMachines@2"]},{"description":"Publish Cobertura or JaCoCo code coverage results from a build","doNotSuggest":false,"ignoreCase":"value","enum":["PublishCodeCoverageResults@1"]},{"description":"Deprecated: This task and it’s companion task (Visual Studio Test Agent Deployment) are deprecated. Use the 'Visual Studio Test' task instead. The VSTest task can run unit as well as functional tests. Run tests on one or more agents using the multi-agent job setting. Use the 'Visual Studio Test Platform' task to run tests without needing Visual Studio on the agent. VSTest task also brings new capabilities such as automatically rerunning failed tests.","deprecationMessage":"RunVisualStudioTestsusingTestAgent is deprecated - Deprecated: This task and it’s companion task (Visual Studio Test Agent Deployment) are deprecated. Use the 'Visual Studio Test' task instead. The VSTest task can run unit as well as functional tests. Run tests on one or more agents using the multi-agent job setting. Use the 'Visual Studio Test Platform' task to run tests without needing Visual Studio on the agent. VSTest task also brings new capabilities such as automatically rerunning failed tests.","doNotSuggest":true,"ignoreCase":"value","enum":["RunVisualStudioTestsusingTestAgent@1"]},{"description":"Execute bash script","doNotSuggest":false,"ignoreCase":"value","enum":["Shellpp@0"]},{"description":"Pause deployment and wait for manual intervention","doNotSuggest":false,"ignoreCase":"value","enum":["ManualIntervention@8"]},{"description":"Install an Apple provisioning profile required to build on a macOS agent machine","doNotSuggest":false,"ignoreCase":"value","enum":["InstallAppleProvisioningProfile@1"]},{"description":"Install an Apple provisioning profile required to build on a macOS agent","doNotSuggest":false,"ignoreCase":"value","enum":["InstallAppleProvisioningProfile@0"]},{"description":"[DEPRECATED] Finish the analysis and upload the results to SonarQube","deprecationMessage":"SonarQubePostTest is deprecated - [DEPRECATED] Finish the analysis and upload the results to SonarQube","doNotSuggest":true,"ignoreCase":"value","enum":["SonarQubePostTest@1"]},{"description":"Indexes repository and stores navigation information","doNotSuggest":false,"ignoreCase":"value","enum":["RichCodeNavIndexer@0"]},{"description":"Creates a PR for a Payload Insertion into VS","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildInsertVsPayload@3"]},{"description":"Creates a PR for a Payload Insertion into VS","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildInsertVsPayload@4"]},{"description":"Create and upload an sdist or wheel to a PyPI-compatible index using Twine","doNotSuggest":false,"ignoreCase":"value","enum":["PyPIPublisher@0"]},{"description":"Run scripts with Knife commands on your Chef workstation","deprecationMessage":"ChefKnife is deprecated - Run scripts with Knife commands on your Chef workstation","doNotSuggest":true,"ignoreCase":"value","enum":["ChefKnife@1"]},{"description":"Find in cache or download a specific version of Go and add it to the PATH","doNotSuggest":false,"ignoreCase":"value","enum":["GoTool@0"]},{"description":"Routes traffic of a Web App to an App Slot by the specified percentage","doNotSuggest":false,"ignoreCase":"value","enum":["azureWebAppRouteTraffic@0"]},{"description":"Generate an .ipa file from Xcode build output using xcrun (Xcode 7 or below)","deprecationMessage":"XcodePackageiOS is deprecated - Generate an .ipa file from Xcode build output using xcrun (Xcode 7 or below)","doNotSuggest":true,"ignoreCase":"value","enum":["XcodePackageiOS@0"]},{"description":"Get, build, or test a Go application, or run a custom Go command","doNotSuggest":false,"ignoreCase":"value","enum":["Go@0"]},{"description":"Replaces ____ and/or XPath for XML documents with User Defined variables or configuration json document","doNotSuggest":false,"ignoreCase":"value","enum":["Tokenizer@2"]},{"description":"Publish Pipeline Metadata to Evidence store","doNotSuggest":false,"ignoreCase":"value","enum":["PublishPipelineMetadata@0"]},{"description":"Build, tag, push, or run Docker images, or run a Docker command","doNotSuggest":false,"ignoreCase":"value","enum":["Docker@1"]},{"description":"Build or push Docker images, login or logout, start or stop containers, or run a Docker command","doNotSuggest":false,"ignoreCase":"value","enum":["Docker@2"]},{"description":"Build, tag, push, or run Docker images, or run a Docker command","doNotSuggest":false,"ignoreCase":"value","enum":["Docker@0"]},{"description":"Publish to Artifact Services Drop - Internal Preview","doNotSuggest":false,"ignoreCase":"value","enum":["artifactDropTask@0"]},{"description":"Queue a job on a Jenkins server","doNotSuggest":false,"ignoreCase":"value","enum":["JenkinsQueueJob@2"]},{"description":"Queue a job on a Jenkins server","doNotSuggest":false,"ignoreCase":"value","enum":["JenkinsQueueJob@1"]},{"description":"Upload files using FTP","doNotSuggest":false,"ignoreCase":"value","enum":["FtpUpload@1"]},{"description":"Upload files using FTP","doNotSuggest":false,"ignoreCase":"value","enum":["FtpUpload@2"]},{"description":"Copy files to remote Windows machines","doNotSuggest":false,"ignoreCase":"value","enum":["WindowsMachineFileCopy@1"]},{"description":"Copy files to remote Windows machines","doNotSuggest":false,"ignoreCase":"value","enum":["WindowsMachineFileCopy@2"]},{"description":"Send an email to 1 or more addresses via the SMTP server you provide","doNotSuggest":false,"ignoreCase":"value","enum":["SendEmail@1"]},{"description":"[Deprecated] Use Gradle","deprecationMessage":"AndroidBuild is deprecated - [Deprecated] Use Gradle","doNotSuggest":true,"ignoreCase":"value","enum":["AndroidBuild@1"]},{"description":"Authenticate for uploading Python distributions using twine. Add '-r FeedName/EndpointName --config-file $(PYPIRC_PATH)' to your twine upload command. For feeds present in this organization, use the feed name as the repository (-r). Otherwise, use the endpoint name defined in the service connection.","doNotSuggest":false,"ignoreCase":"value","enum":["TwineAuthenticate@1"]},{"description":"Authenticate for uploading Python distributions using twine. Add '-r FeedName/EndpointName --config-file $(PYPIRC_PATH)' to your twine upload command. For feeds present in this organization, use the feed name as the repository (-r). Otherwise, use the endpoint name defined in the service connection.","doNotSuggest":false,"ignoreCase":"value","enum":["TwineAuthenticate@0"]},{"description":"Deploy a website or web application using Web Deploy","doNotSuggest":false,"ignoreCase":"value","enum":["IISWebAppDeploymentOnMachineGroup@0"]},{"description":"Run a Python file or inline script","doNotSuggest":false,"ignoreCase":"value","enum":["PythonScript@0"]},{"description":"Install Helm on an agent machine","doNotSuggest":false,"ignoreCase":"value","enum":["HelmInstaller@1"]},{"description":"Install Helm and Kubernetes on an agent machine","doNotSuggest":false,"ignoreCase":"value","enum":["HelmInstaller@0"]},{"description":"[Deprecated] Upgrade to free version of Xamarin: https://store.xamarin.com","deprecationMessage":"XamarinLicense is deprecated - [Deprecated] Upgrade to free version of Xamarin: https://store.xamarin.com","doNotSuggest":true,"ignoreCase":"value","enum":["XamarinLicense@1"]},{"description":"Configure NuGet tools to authenticate with Azure Artifacts and other NuGet repositories. Requires NuGet >= 4.8.5385, dotnet >= 2.1.400, or MSBuild >= 15.8.166.59604","doNotSuggest":false,"ignoreCase":"value","enum":["NuGetAuthenticate@0"]},{"description":"Include with your build to enable automatic Component Governance detection.","doNotSuggest":false,"ignoreCase":"value","enum":["ComponentGovernanceComponentDetection@0"]},{"description":"Restore your nuget packages using dotnet CLI","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadGitHubNugetPackage@1"]},{"description":"Provides credentials for Azure Artifacts feeds and external maven repositories","doNotSuggest":false,"ignoreCase":"value","enum":["MavenAuthenticate@0"]},{"description":"Use this task under deploy phase provider to create a resource dynamically","doNotSuggest":false,"ignoreCase":"value","enum":["ReviewApp@0"]},{"description":"Acquire a specific version of Java from a user-supplied Azure blob or the tool cache and sets JAVA_HOME","doNotSuggest":false,"ignoreCase":"value","enum":["JavaToolInstaller@0"]},{"description":"Deploy to Chef environments by editing environment attributes","deprecationMessage":"Chef is deprecated - Deploy to Chef environments by editing environment attributes","doNotSuggest":true,"ignoreCase":"value","enum":["Chef@1"]},{"description":"Update a function app with .NET, Python, JavaScript, PowerShell, Java based web applications","doNotSuggest":false,"ignoreCase":"value","enum":["AzureFunctionApp@1"]},{"description":"Don't use this task if you're also using the npm task. Provides npm credentials to an .npmrc file in your repository for the scope of the build. This enables npm task runners like gulp and Grunt to authenticate with private registries.","doNotSuggest":false,"ignoreCase":"value","enum":["npmAuthenticate@0"]},{"description":"Build with MSBuild","doNotSuggest":false,"ignoreCase":"value","enum":["MSBuild@1"]},{"description":"Adds a coverage trend summary section to the build report.","doNotSuggest":false,"ignoreCase":"value","enum":["CoverageGate@1"]},{"description":"Build a machine image using Packer, which may be used for Azure Virtual machine scale set deployment","doNotSuggest":false,"ignoreCase":"value","enum":["PackerBuild@1"]},{"description":"Build a machine image using Packer, which may be used for Azure Virtual machine scale set deployment","doNotSuggest":false,"ignoreCase":"value","enum":["PackerBuild@0"]},{"description":"Installs and configures the MicroBuild signing plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSigningPlugin@4"]},{"description":"Installs and configures the MicroBuild signing plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSigningPlugin@1"]},{"description":"[Test-Xamarin-0.999.10 (all-lock)] Installs and configures the MicroBuild signing plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSigningPlugin@0"]},{"description":"Installs and configures the MicroBuild signing plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSigningPlugin@3"]},{"description":"Installs and configures the MicroBuild signing plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSigningPlugin@2"]},{"description":"Deprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","deprecationMessage":"NuGetPackager is deprecated - Deprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","doNotSuggest":true,"ignoreCase":"value","enum":["NuGetPackager@0"]},{"description":"Automatically updates the versions of a packaged Service Fabric application.","doNotSuggest":false,"ignoreCase":"value","enum":["ServiceFabricUpdateAppVersions@1"]},{"description":"Automatically update portions of application and service manifests in a packaged Azure Service Fabric application","doNotSuggest":false,"ignoreCase":"value","enum":["ServiceFabricUpdateManifests@2"]},{"description":"Install a specified version of Duffle for installing and managing CNAB bundles","doNotSuggest":false,"ignoreCase":"value","enum":["DuffleInstaller@0"]},{"description":"Observe the configured Azure Monitor rules for active alerts","doNotSuggest":false,"ignoreCase":"value","enum":["AzureMonitor@1"]},{"description":"Observe the configured classic Azure Monitor rules for active alerts","deprecationMessage":"AzureMonitor is deprecated - Observe the configured classic Azure Monitor rules for active alerts","doNotSuggest":true,"ignoreCase":"value","enum":["AzureMonitor@0"]},{"description":"Task to generate runsettings and ADO Drop Urls as artifacts.","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildGenerateTestArtifacts@1"]},{"description":"Connect or disconnect an Azure virtual machine's network interface to a Load Balancer's back end address pool","doNotSuggest":false,"ignoreCase":"value","enum":["AzureNLBManagement@1"]},{"description":"Run an Apache JMeter load test in the cloud","deprecationMessage":"ApacheJMeterLoadTest is deprecated - Run an Apache JMeter load test in the cloud","doNotSuggest":true,"ignoreCase":"value","enum":["ApacheJMeterLoadTest@1"]},{"description":"Build, push or run multi-container Docker applications. Task can be used with Docker or Azure Container registry.","doNotSuggest":false,"ignoreCase":"value","enum":["DockerCompose@0"]},{"description":"Configure alerts on available metrics for an Azure resource (Deprecated)","doNotSuggest":false,"ignoreCase":"value","enum":["AzureMonitorAlerts@0"]},{"description":"[Deprecated] Test mobile apps with Xamarin Test Cloud using Xamarin.UITest. Instead, use the 'App Center test' task.","deprecationMessage":"XamarinTestCloud is deprecated - [Deprecated] Test mobile apps with Xamarin Test Cloud using Xamarin.UITest. Instead, use the 'App Center test' task.","doNotSuggest":true,"ignoreCase":"value","enum":["XamarinTestCloud@1"]},{"description":"Deploy an Azure Service Fabric application to a cluster","doNotSuggest":false,"ignoreCase":"value","enum":["ServiceFabricDeploy@1"]},{"description":"Uploads MicroBuild telemetry. This step should be added at the end of every definition using MicroBuild tasks.","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildCleanup@1"]},{"description":"Installs and configures the MicroBuild OptProf plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildOptProfPlugin@3"]},{"description":"Installs and configures the MicroBuild OptProf plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildOptProfPlugin@2"]},{"description":"Installs and configures the MicroBuild OptProf plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildOptProfPlugin@6"]},{"description":"Installs and configures the MicroBuild OptProf plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildOptProfPlugin@4"]},{"description":"Installs and configures the MicroBuild OptProf plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildOptProfPlugin@5"]},{"description":"Installs and configures the MicroBuild OptProf plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildOptProfPlugin@1"]},{"description":"Build an Xcode workspace on Mac OS","doNotSuggest":false,"ignoreCase":"value","enum":["Xcode@2"]},{"description":"Build, test, or archive an Xcode workspace on macOS. Optionally package an app.","doNotSuggest":false,"ignoreCase":"value","enum":["Xcode@5"]},{"description":"Build an Xcode workspace on macOS","doNotSuggest":false,"ignoreCase":"value","enum":["Xcode@3"]},{"description":"Build, test, or archive an Xcode workspace on macOS. Optionally package an app.","doNotSuggest":false,"ignoreCase":"value","enum":["Xcode@4"]},{"description":"Deprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","deprecationMessage":"NuGetPublisher is deprecated - Deprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","doNotSuggest":true,"ignoreCase":"value","enum":["NuGetPublisher@0"]},{"description":"Updates the version number of the assemblies to match the build number","doNotSuggest":false,"ignoreCase":"value","enum":["VersionAssemblies@2"]},{"description":"Execute a work item query and check the number of items returned","doNotSuggest":false,"ignoreCase":"value","enum":["queryWorkItems@0"]},{"description":"Installs and configures the MicroBuild IBCMerge plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildIBCMergePlugin@1"]},{"description":"Installs and configures the MicroBuild IBCMerge plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildIBCMergePlugin@0"]},{"description":"Deploy containers to Azure App Service","doNotSuggest":false,"ignoreCase":"value","enum":["AzureWebAppContainer@1"]},{"description":"Deploy a SQL Server database using DACPAC or SQL scripts","doNotSuggest":false,"ignoreCase":"value","enum":["SqlDacpacDeploymentOnMachineGroup@0"]},{"description":"Cache files between runs","doNotSuggest":false,"ignoreCase":"value","enum":["CacheBeta@1"]},{"description":"Cache files between runs","doNotSuggest":false,"ignoreCase":"value","enum":["Cache@2"]},{"description":"Cache files between runs","doNotSuggest":false,"ignoreCase":"value","enum":["CacheBeta@0"]},{"description":"Installs and configures the MicroBuild FXCop plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildFXCopPlugin@2"]},{"description":"Build with the CMake cross-platform build system","doNotSuggest":false,"ignoreCase":"value","enum":["CMake@1"]},{"description":"Test app packages with Visual Studio App Center","doNotSuggest":false,"ignoreCase":"value","enum":["AppCenterTest@1"]},{"description":"Test mobile app packages with Visual Studio Mobile Center.","doNotSuggest":false,"ignoreCase":"value","enum":["VSMobileCenterTest@0"]},{"description":"Finds or Downloads and caches specified version spec of EsrpClient CLI and adds it to the PATH. In addition it will set esrpclient.toolpath and esrpclient.toolname task output variables which you can use in subsequent tasks or build scripts","doNotSuggest":false,"ignoreCase":"value","enum":["EsrpClientTool@1"]},{"description":"Download a secure file to the agent machine","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadSecureFile@1"]},{"description":"Use the specified version of Ruby from the tool cache, optionally adding it to the PATH","doNotSuggest":false,"ignoreCase":"value","enum":["UseRubyVersion@0"]},{"description":"Run the Grunt JavaScript task runner","doNotSuggest":false,"ignoreCase":"value","enum":["Grunt@0"]},{"description":"Deploy an Azure SQL Database using DACPAC or run scripts using SQLCMD","doNotSuggest":false,"ignoreCase":"value","enum":["SqlAzureDacpacDeployment@1"]},{"description":"Uses container-structure-test (https://github.com/GoogleContainerTools/container-structure-test) to validate the structure of an image based on four categories of tests - command tests, file existence tests, file content tests and metadata tests","doNotSuggest":false,"ignoreCase":"value","enum":["ContainerStructureTest@0"]},{"description":"Deploy using MSDeploy, then create/update websites and app pools","deprecationMessage":"IISWebAppDeployment is deprecated - Deploy using MSDeploy, then create/update websites and app pools","doNotSuggest":true,"ignoreCase":"value","enum":["IISWebAppDeployment@1"]},{"description":"Run a load test in the cloud with Azure Pipelines","deprecationMessage":"CloudLoadTest is deprecated - Run a load test in the cloud with Azure Pipelines","doNotSuggest":true,"ignoreCase":"value","enum":["CloudLoadTest@1"]},{"description":"Validates that pipelines use secure and compliant Azure DevOps pools","doNotSuggest":false,"ignoreCase":"value","enum":["1ESHostedPoolValidation@1"]},{"description":"Download from Artifact Services Drop - Internal Preview","doNotSuggest":false,"ignoreCase":"value","enum":["artifactDropDownloadTask@0"]},{"description":"Install Kubectl on agent machine","doNotSuggest":false,"ignoreCase":"value","enum":["KubectlInstaller@0"]},{"description":"Run a command line script using Bash on Linux and macOS and cmd.exe on Windows","doNotSuggest":false,"ignoreCase":"value","enum":["CmdLine@2"]},{"description":"Run a command line with arguments","doNotSuggest":false,"ignoreCase":"value","enum":["CmdLine@1"]},{"description":"Deprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","deprecationMessage":"NuGet is deprecated - Deprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","doNotSuggest":true,"ignoreCase":"value","enum":["NuGet@0"]},{"description":"Container Build Task","doNotSuggest":false,"ignoreCase":"value","enum":["ContainerBuild@0"]},{"description":"Send end job telemetry for .NET Core builds","doNotSuggest":false,"ignoreCase":"value","enum":["SendEndTelemetry@0"]},{"description":"Restores NuGet packages in preparation for a Visual Studio Build step.","doNotSuggest":false,"ignoreCase":"value","enum":["NuGetRestore@1"]},{"description":"Restore, pack, or push NuGet packages, or run a NuGet command. Supports NuGet.org and authenticated feeds like Azure Artifacts and MyGet. Uses NuGet.exe and works with .NET Framework apps. For .NET Core and .NET Standard apps, use the .NET Core task.","doNotSuggest":false,"ignoreCase":"value","enum":["NuGetCommand@2"]},{"description":"Installs or restores missing NuGet packages. Use NuGetAuthenticate@0 task for latest capabilities.","doNotSuggest":false,"ignoreCase":"value","enum":["NuGetInstaller@0"]},{"description":"Invokes the VS Tools for Docker script with optional overrides","deprecationMessage":"DockerPublish is deprecated - Invokes the VS Tools for Docker script with optional overrides","doNotSuggest":true,"ignoreCase":"value","enum":["DockerPublish@0"]},{"description":"Delay further execution of a workflow by a fixed time","doNotSuggest":false,"ignoreCase":"value","enum":["Delay@1"]},{"description":"Submits Mac files to PRSS for signing","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSignMacFiles@1"]},{"description":"Submits Mac files to PRSS for signing","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSignMacFiles@0"]},{"description":"Build an iOS app with Xamarin on macOS","doNotSuggest":false,"ignoreCase":"value","enum":["XamariniOS@2"]},{"description":"Build an iOS app with Xamarin on macOS","doNotSuggest":false,"ignoreCase":"value","enum":["XamariniOS@1"]},{"description":"Analyze repository and generate data files to enable semantic code browsing.","doNotSuggest":false,"ignoreCase":"value","enum":["Ref12Analyze@0"]},{"description":"Publish test results to Azure Pipelines","doNotSuggest":false,"ignoreCase":"value","enum":["PublishTestResults@1"]},{"description":"Publish test results to Azure Pipelines","doNotSuggest":false,"ignoreCase":"value","enum":["PublishTestResults@2"]},{"description":"Copy files to Azure Blob Storage or virtual machines","doNotSuggest":false,"ignoreCase":"value","enum":["AzureFileCopy@1"]},{"description":"Copy files to Azure Blob Storage or virtual machines","doNotSuggest":false,"ignoreCase":"value","enum":["AzureFileCopy@2"]},{"description":"Copy files to Azure Blob Storage or virtual machines","doNotSuggest":false,"ignoreCase":"value","enum":["AzureFileCopy@3"]},{"description":"Copy files to Azure Blob Storage or virtual machines","doNotSuggest":false,"ignoreCase":"value","enum":["AzureFileCopy@4"]},{"description":"Installs and configures the MicroBuild swix plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSwixPlugin@3"]},{"description":"Installs and configures the MicroBuild swix plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSwixPlugin@4"]},{"description":"Installs and configures the MicroBuild swix plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSwixPlugin@2"]},{"description":"Installs and configures the MicroBuild swix plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildSwixPlugin@1"]},{"description":"Index your source code and publish symbols to a file share or Azure Artifacts symbol server","doNotSuggest":false,"ignoreCase":"value","enum":["PublishSymbols@2"]},{"description":"Index your source code and publish symbols to a file share","doNotSuggest":false,"ignoreCase":"value","enum":["PublishSymbols@1"]},{"description":"Copy files or build artifacts to a remote machine over SSH","doNotSuggest":false,"ignoreCase":"value","enum":["CopyFilesOverSSH@0"]},{"description":"Build using a Gradle wrapper script","doNotSuggest":false,"ignoreCase":"value","enum":["Gradle@2"]},{"description":"Build using a Gradle wrapper script","doNotSuggest":false,"ignoreCase":"value","enum":["Gradle@3"]},{"description":"Build using a Gradle wrapper script","doNotSuggest":false,"ignoreCase":"value","enum":["Gradle@1"]},{"description":"Replaces tokens in a file using RegEx. Values come from any variable defined in the current Environment.","doNotSuggest":false,"ignoreCase":"value","enum":["ReplaceTokens@1"]},{"description":"Installs and configures the MicroBuild localization plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildLocalizationPlugin@1"]},{"description":"Installs and configures the MicroBuild localization plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildLocalizationPlugin@4"]},{"description":"Installs and configures the MicroBuild localization plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildLocalizationPlugin@3"]},{"description":"Installs and configures the MicroBuild localization plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildLocalizationPlugin@2"]},{"description":"Microsoft Internal tool for Malware Scanning of files using ESRP Service","doNotSuggest":false,"ignoreCase":"value","enum":["EsrpMalwareScanning@1"]},{"description":"Distribute app builds to testers and users via Visual Studio App Center","doNotSuggest":false,"ignoreCase":"value","enum":["AppCenterDistribute@1"]},{"description":"Distribute app builds to testers and users via Visual Studio App Center","doNotSuggest":false,"ignoreCase":"value","enum":["AppCenterDistribute@2"]},{"description":"Distribute app builds to testers and users via Visual Studio App Center","doNotSuggest":false,"ignoreCase":"value","enum":["AppCenterDistribute@3"]},{"description":"Distribute app builds to testers and users via App Center","doNotSuggest":false,"ignoreCase":"value","enum":["AppCenterDistribute@0"]},{"description":"Acquires a specific version of NuGet from the internet or the tools cache and adds it to the PATH. Use this task to change the version of NuGet used in the NuGet tasks.","doNotSuggest":false,"ignoreCase":"value","enum":["NuGetToolInstaller@1"]},{"description":"Acquires a specific version of NuGet from the internet or the tools cache and adds it to the PATH. Use this task to change the version of NuGet used in the NuGet tasks.","doNotSuggest":false,"ignoreCase":"value","enum":["NuGetToolInstaller@0"]},{"description":"Invokes web deploy to Azure website, substituting any Environment variables into the SetParameters.xml file","deprecationMessage":"AzureWebDeploy is deprecated - Invokes web deploy to Azure website, substituting any Environment variables into the SetParameters.xml file","doNotSuggest":true,"ignoreCase":"value","enum":["AzureWebDeploy@0"]},{"description":"Generic LSBuild wrapper which streamlines the localization build process and optionally checks-in resulting localized files to a repo","doNotSuggest":false,"ignoreCase":"value","enum":["OneLocBuild@2"]},{"description":"Download artifacts produced by a Jenkins job","doNotSuggest":false,"ignoreCase":"value","enum":["JenkinsDownloadArtifacts@1"]},{"description":"Update a function app with a Docker container","doNotSuggest":false,"ignoreCase":"value","enum":["AzureFunctionAppContainer@1"]},{"description":"Decrypt a file using OpenSSL","doNotSuggest":false,"ignoreCase":"value","enum":["DecryptFile@1"]},{"description":"Deploy, configure, update a Kubernetes cluster in Azure Container Service by running helm commands","doNotSuggest":false,"ignoreCase":"value","enum":["HelmDeploy@0"]},{"description":"Install an Apple certificate required to build on a macOS agent machine","doNotSuggest":false,"ignoreCase":"value","enum":["InstallAppleCertificate@2"]},{"description":"Install an Apple certificate required to build on a macOS agent","doNotSuggest":false,"ignoreCase":"value","enum":["InstallAppleCertificate@1"]},{"description":"Install an Apple certificate required to build on a macOS agent","doNotSuggest":false,"ignoreCase":"value","enum":["InstallAppleCertificate@0"]},{"description":"Microsoft Internal tool for Code Signing files using ESRP Service","doNotSuggest":false,"ignoreCase":"value","enum":["EsrpCodeSigning@1"]},{"description":"Invoke an Azure Function","doNotSuggest":false,"ignoreCase":"value","enum":["AzureFunction@1"]},{"description":"Invoke Azure function as a part of your process.","doNotSuggest":false,"ignoreCase":"value","enum":["AzureFunction@0"]},{"description":"A task to scan for vulnerabilities in nuget files.","doNotSuggest":false,"ignoreCase":"value","enum":["nuget-security-analysis@0"]},{"description":"Provides a report on database model changes since the last build","doNotSuggest":false,"ignoreCase":"value","enum":["DacPacReport@1"]},{"description":"Downloads a GitHub Release from a repository","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadGitHubRelease@0"]},{"description":"Run shell commands or a script on a remote machine using SSH","doNotSuggest":false,"ignoreCase":"value","enum":["SSH@0"]},{"description":"Publish (upload) a file or directory as a named artifact for the current run","doNotSuggest":false,"ignoreCase":"value","enum":["PublishPipelineArtifact@1"]},{"description":"Publish a local directory or file as a named artifact for the current pipeline","deprecationMessage":"PublishPipelineArtifact is deprecated - Publish a local directory or file as a named artifact for the current pipeline","doNotSuggest":true,"ignoreCase":"value","enum":["PublishPipelineArtifact@0"]},{"description":"[DEPRECATED] Fetch the Quality Profile from SonarQube to configure the analysis","deprecationMessage":"SonarQubePreBuild is deprecated - [DEPRECATED] Fetch the Quality Profile from SonarQube to configure the analysis","doNotSuggest":true,"ignoreCase":"value","enum":["SonarQubePreBuild@1"]},{"description":"Builds a VS Bootstrapper including the changes of the manifests from one or more components","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildBuildVSBootstrapper@2"]},{"description":"Builds a VS Bootstrapper including the changes of the manifests from one or more components","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildBuildVSBootstrapper@1"]},{"description":"Download artifacts from a file share, like \\\\share\\drop","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadFileshareArtifacts@1"]},{"description":"Deploy, configure, update a Kubernetes cluster in Azure Container Service by running kubectl commands","doNotSuggest":false,"ignoreCase":"value","enum":["Kubernetes@1"]},{"description":"Deploy, configure, update a Kubernetes cluster in Azure Container Service by running kubectl commands","doNotSuggest":false,"ignoreCase":"value","enum":["Kubernetes@0"]},{"description":"Build and deploy an Azure IoT Edge image","doNotSuggest":false,"ignoreCase":"value","enum":["AzureIoTEdge@2"]},{"description":"Deploy a Docker Compose application to an Azure Service Fabric cluster","doNotSuggest":false,"ignoreCase":"value","enum":["ServiceFabricComposeDeploy@0"]},{"description":"Sign and align Android APK files","doNotSuggest":false,"ignoreCase":"value","enum":["AndroidSigning@2"]},{"description":"Sign and align Android APK files","doNotSuggest":false,"ignoreCase":"value","enum":["AndroidSigning@1"]},{"description":"Sign and align Android APK files","doNotSuggest":false,"ignoreCase":"value","enum":["AndroidSigning@3"]},{"description":"Download a named artifact from a pipeline to a local path","deprecationMessage":"DownloadPipelineArtifact is deprecated - Download a named artifact from a pipeline to a local path","doNotSuggest":true,"ignoreCase":"value","enum":["DownloadPipelineArtifact@1"]},{"description":"Downloads an artifact associated with a pipeline","deprecationMessage":"DownloadPipelineArtifact is deprecated - Downloads an artifact associated with a pipeline","doNotSuggest":true,"ignoreCase":"value","enum":["DownloadPipelineArtifact@0"]},{"description":"Download build and pipeline artifacts","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadPipelineArtifact@2"]},{"description":"Use the specified version of Python from the tool cache, optionally adding it to the PATH","doNotSuggest":false,"ignoreCase":"value","enum":["UsePythonVersion@0"]},{"description":"Scan accessibility issues in an Azure DevOps pipeline","doNotSuggest":false,"ignoreCase":"value","enum":["accessibility-insights@1"]},{"description":"Uploads a Folder to the Azure DevOps Drop Service","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildUploadVstsDropFolder@2"]},{"description":"Uploads a Folder to the Azure DevOps Drop Service","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildUploadVstsDropFolder@1"]},{"description":"Run a PowerShell script in the context of an Azure Service Fabric cluster connection","doNotSuggest":false,"ignoreCase":"value","enum":["ServiceFabricPowerShell@1"]},{"description":"Run tests with Visual Studio test runner","doNotSuggest":false,"ignoreCase":"value","enum":["VSTest@1"]},{"description":"Run unit and functional tests (Selenium, Appium, Coded UI test, etc.) using the Visual Studio Test (VsTest) runner. Test frameworks that have a Visual Studio test adapter such as MsTest, xUnit, NUnit, Chutzpah (for JavaScript tests using QUnit, Mocha and Jasmine), etc. can be run. Tests can be distributed on multiple agents using this task (version 2).","doNotSuggest":false,"ignoreCase":"value","enum":["VSTest@2"]},{"description":"[PREVIEW] Pause a pipeline run to wait for manual interaction. Works only with YAML pipelines.","doNotSuggest":false,"ignoreCase":"value","enum":["ManualValidation@0"]},{"description":"Promote nuget packages to a view in VS and VS-CoreXTFeeds","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildPromoteNugetPackages@2"]},{"description":"Build with Apache Ant","doNotSuggest":false,"ignoreCase":"value","enum":["Ant@1"]},{"description":"Deprecated: Instead, use the 'Visual Studio Test' task to run unit and functional tests","deprecationMessage":"DeployVisualStudioTestAgent is deprecated - Deprecated: Instead, use the 'Visual Studio Test' task to run unit and functional tests","doNotSuggest":true,"ignoreCase":"value","enum":["DeployVisualStudioTestAgent@2"]},{"description":"Deploy and configure Test Agent to run tests on a set of machines","doNotSuggest":false,"ignoreCase":"value","enum":["DeployVisualStudioTestAgent@1"]},{"description":"This task is deprecated. Use `conda` directly in script to work with Anaconda environments.","deprecationMessage":"CondaEnvironment is deprecated - This task is deprecated. Use `conda` directly in script to work with Anaconda environments.","doNotSuggest":true,"ignoreCase":"value","enum":["CondaEnvironment@1"]},{"description":"Create and activate a Conda environment","doNotSuggest":false,"ignoreCase":"value","enum":["CondaEnvironment@0"]},{"description":"Run a Windows command or batch script and optionally allow it to change the environment","doNotSuggest":false,"ignoreCase":"value","enum":["BatchScript@1"]},{"description":"Install npm packages from GitHub.","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadGithubNpmPackage@1"]},{"description":"Build with MSBuild and set the Visual Studio version property","doNotSuggest":false,"ignoreCase":"value","enum":["VSBuild@1"]},{"description":"Download Azure Key Vault secrets","doNotSuggest":false,"ignoreCase":"value","enum":["AzureKeyVault@1"]},{"description":"Download Azure Key Vault secrets","doNotSuggest":false,"ignoreCase":"value","enum":["AzureKeyVault@2"]},{"description":"Acquire a specific version of the .NET Core SDK from the internet or local cache and add it to the PATH","deprecationMessage":"DotNetCoreInstaller is deprecated - Acquire a specific version of the .NET Core SDK from the internet or local cache and add it to the PATH","doNotSuggest":true,"ignoreCase":"value","enum":["DotNetCoreInstaller@1"]},{"description":"Acquires a specific version of the .NET Core SDK from the internet or the local cache and adds it to the PATH. Use this task to change the version of .NET Core used in subsequent tasks. Additionally provides proxy support.","doNotSuggest":false,"ignoreCase":"value","enum":["UseDotNet@2"]},{"description":"Acquire a specific version of the .NET Core SDK from the internet or local cache and add it to the PATH","doNotSuggest":false,"ignoreCase":"value","enum":["DotNetCoreInstaller@0"]},{"description":"Start, stop, restart, slot swap, slot delete, install site extensions or enable continuous monitoring for an Azure App Service","doNotSuggest":false,"ignoreCase":"value","enum":["AzureAppServiceManage@0"]},{"description":"Install Azure Func Core Tools","doNotSuggest":false,"ignoreCase":"value","enum":["FuncToolsInstaller@0"]},{"description":"Replace tokens with variable values in XML or JSON configuration files","doNotSuggest":false,"ignoreCase":"value","enum":["FileTransform@1"]},{"description":"Replace tokens with variable values in XML or JSON configuration files","doNotSuggest":false,"ignoreCase":"value","enum":["FileTransform@2"]},{"description":"Verifies that mac files have been correctly codesigned. This can only be used on Mac hosts.","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildMacSignVerify@0"]},{"description":"Extract a variety of archive and compression files such as .7z, .rar, .tar.gz, and .zip","doNotSuggest":false,"ignoreCase":"value","enum":["ExtractFiles@1"]},{"description":"Build an Android app with Xamarin","doNotSuggest":false,"ignoreCase":"value","enum":["XamarinAndroid@1"]},{"description":"Creates a manifest.json and bsi.json for all the files in a folder. This generated manifest can be used to validate the contents of the folder in the future.","doNotSuggest":false,"ignoreCase":"value","enum":["ManifestGeneratorTask@0"]},{"description":"(Deprecated) Use the PowerShell task version 2 for online scripts","deprecationMessage":"Powershellpp is deprecated - (Deprecated) Use the PowerShell task version 2 for online scripts","doNotSuggest":true,"ignoreCase":"value","enum":["Powershellpp@0"]},{"description":"[DEPRECATED] Use the Copy Files task and the Publish Build Artifacts task instead","deprecationMessage":"CopyPublishBuildArtifacts is deprecated - [DEPRECATED] Use the Copy Files task and the Publish Build Artifacts task instead","doNotSuggest":true,"ignoreCase":"value","enum":["CopyPublishBuildArtifacts@1"]},{"description":"Execute Bash on POSIX, CMD on Windows","doNotSuggest":false,"ignoreCase":"value","enum":["BashOrCmd@0"]},{"description":"Download a package from a package management feed in Azure Artifacts","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadPackage@1"]},{"description":"Download a package from a package management feed in Azure Artifacts","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadPackage@0"]},{"description":"This task is deprecated.","deprecationMessage":"MicroBuildStaticDrop is deprecated - This task is deprecated.","doNotSuggest":true,"ignoreCase":"value","enum":["MicroBuildStaticDrop@1"]},{"description":"Deploy an Azure Resource Manager (ARM) template to a resource group and manage virtual machines","doNotSuggest":false,"ignoreCase":"value","enum":["AzureResourceGroupDeployment@2"]},{"description":"Deploy, start, stop, delete Azure Resource Groups","deprecationMessage":"AzureResourceGroupDeployment is deprecated - Deploy, start, stop, delete Azure Resource Groups","doNotSuggest":true,"ignoreCase":"value","enum":["AzureResourceGroupDeployment@1"]},{"description":"Deploy an Azure Resource Manager (ARM) template to all the deployment scopes","doNotSuggest":false,"ignoreCase":"value","enum":["AzureResourceManagerTemplateDeployment@3"]},{"description":"Invoke REST API as a part of your process.","doNotSuggest":false,"ignoreCase":"value","enum":["InvokeRESTAPI@0"]},{"description":"Invoke a REST API as a part of your pipeline.","doNotSuggest":false,"ignoreCase":"value","enum":["InvokeRESTAPI@1"]},{"description":"Archive files using compression formats such as .7z, .rar, .tar.gz, and .zip.","doNotSuggest":false,"ignoreCase":"value","enum":["ArchiveFiles@1"]},{"description":"Compress files into .7z, .tar.gz, or .zip","doNotSuggest":false,"ignoreCase":"value","enum":["ArchiveFiles@2"]},{"description":"Write a comment to your Github entity i.e. issue or a Pull Request (PR)","doNotSuggest":false,"ignoreCase":"value","enum":["GitHubComment@0"]},{"description":"Copy files from a source folder to a target folder using patterns matching file paths (not folder paths)","doNotSuggest":false,"ignoreCase":"value","enum":["CopyFiles@2"]},{"description":"Copy files from source folder to target folder using minimatch patterns (The minimatch patterns will only match file paths, not folder paths)","doNotSuggest":false,"ignoreCase":"value","enum":["CopyFiles@1"]},{"description":"Run your scripts and make changes to your Azure Database for MySQL","doNotSuggest":false,"ignoreCase":"value","enum":["AzureMysqlDeployment@1"]},{"description":"Install and publish npm packages, or run an npm command. Supports npmjs.com and authenticated registries like Azure Artifacts.","doNotSuggest":false,"ignoreCase":"value","enum":["Npm@1"]},{"description":"Run an npm command. Use NpmAuthenticate@0 task for latest capabilities.","doNotSuggest":false,"ignoreCase":"value","enum":["Npm@0"]},{"description":"Validates a given drop against a manifest generated at build time to verify the integrity of the drop.","doNotSuggest":false,"ignoreCase":"value","enum":["DropValidatorTask@0"]},{"description":"[PREVIEW] Build and deploy an Azure Static Web App","doNotSuggest":false,"ignoreCase":"value","enum":["AzureStaticWebApp@0"]},{"description":"Set up a Node.js environment and add it to the PATH, additionally providing proxy support","doNotSuggest":false,"ignoreCase":"value","enum":["UseNode@1"]},{"description":"Finds or downloads and caches the specified version spec of Node.js and adds it to the PATH","doNotSuggest":false,"ignoreCase":"value","enum":["NodeTool@0"]},{"description":"UnZip a package","doNotSuggest":false,"ignoreCase":"value","enum":["unzip@0"]},{"description":"Deploy a SQL Server database using DACPAC","deprecationMessage":"SqlServerDacpacDeployment is deprecated - Deploy a SQL Server database using DACPAC","doNotSuggest":true,"ignoreCase":"value","enum":["SqlServerDacpacDeployment@1"]},{"description":"Acquire the test platform from nuget.org or the tool cache. Satisfies the ‘vstest’ demand and can be used for running tests and collecting diagnostic data using the Visual Studio Test task.","doNotSuggest":false,"ignoreCase":"value","enum":["VisualStudioTestPlatformInstaller@1"]},{"description":"Sends a message to Azure Service Bus using a service connection (no agent is required)","doNotSuggest":false,"ignoreCase":"value","enum":["PublishToAzureServiceBus@1"]},{"description":"Sends a message to azure service bus using a service connection (no agent required).","doNotSuggest":false,"ignoreCase":"value","enum":["PublishToAzureServiceBus@0"]},{"description":"Use Kubernetes manifest files to deploy to clusters or even bake the manifest files to be used for deployments using Helm charts","doNotSuggest":false,"ignoreCase":"value","enum":["KubernetesManifest@0"]},{"description":"Download files that were saved as artifacts of a completed build","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadBuildArtifacts@1"]},{"description":"Download files that were saved as artifacts of a completed build","doNotSuggest":false,"ignoreCase":"value","enum":["DownloadBuildArtifacts@0"]},{"description":"Install CocoaPods dependencies for Swift and Objective-C Cocoa projects","doNotSuggest":false,"ignoreCase":"value","enum":["CocoaPods@0"]},{"description":"Archives symbols on Symweb.","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildArchiveSymbols@1"]},{"description":"Deploy applications to Azure Spring Cloud and manage deployments.","doNotSuggest":false,"ignoreCase":"value","enum":["AzureSpringCloud@0"]},{"description":"Deploy an Azure Web App for Linux or Windows","doNotSuggest":false,"ignoreCase":"value","enum":["AzureWebApp@1"]},{"description":"Run Azure CLI commands against an Azure subscription in a Shell script when running on Linux agent or Batch script when running on Windows agent.","doNotSuggest":false,"ignoreCase":"value","enum":["AzureCLI@1"]},{"description":"Run Azure CLI commands against an Azure subscription in a PowerShell Core/Shell script when running on Linux agent or PowerShell/PowerShell Core/Batch script when running on Windows agent.","doNotSuggest":false,"ignoreCase":"value","enum":["AzureCLI@2"]},{"description":"Run a Shell or Batch script with Azure CLI commands against an azure subscription","doNotSuggest":false,"ignoreCase":"value","enum":["AzureCLI@0"]},{"description":"Installs and configures the MicroBuild VC Error Codes plugin for use during the build","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildVCErrorCodesPlugin@2"]},{"description":"Create and start an Azure Cosmos DB Emulator container for testing","doNotSuggest":false,"ignoreCase":"value","enum":["CosmosDbEmulator@2"]},{"description":"Verifies that files have been correctly codesigned","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildCodesignVerify@2"]},{"description":"Verifies that files have been correctly codesigned","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildCodesignVerify@3"]},{"description":"Create, edit, or delete a GitHub release","doNotSuggest":false,"ignoreCase":"value","enum":["GitHubRelease@1"]},{"description":"Create, edit, or delete a GitHub release","doNotSuggest":false,"ignoreCase":"value","enum":["GitHubRelease@0"]},{"description":"Use cURL to upload files with FTP, FTPS, SFTP, HTTP, and more.","doNotSuggest":false,"ignoreCase":"value","enum":["cURLUploader@1"]},{"description":"Use cURL's supported protocols to upload files","doNotSuggest":false,"ignoreCase":"value","enum":["cURLUploader@2"]},{"description":"Update/Add App settings an Azure Web App for Linux or Windows","doNotSuggest":false,"ignoreCase":"value","enum":["AzureAppServiceSettings@1"]},{"description":"Download or publish Universal Packages","doNotSuggest":false,"ignoreCase":"value","enum":["UniversalPackages@0"]},{"description":"Security and compliance assessment for Azure Policy","doNotSuggest":false,"ignoreCase":"value","enum":["AzurePolicyCheckGate@0"]},{"description":"Deploy Azure function to Kubernetes cluster.","doNotSuggest":false,"ignoreCase":"value","enum":["AzureFunctionOnKubernetes@0"]},{"description":"Retains one or more Azure DevOps Drops permanently","doNotSuggest":false,"ignoreCase":"value","enum":["MicroBuildRetainVstsDrops@1"]},{"description":"Run a shell script using Bash","doNotSuggest":false,"ignoreCase":"value","enum":["ShellScript@2"]},{"description":"Run a Bash script on macOS, Linux, or Windows","doNotSuggest":false,"ignoreCase":"value","enum":["Bash@3"]},{"description":"Publish build artifacts to Azure Pipelines or a Windows file share","doNotSuggest":false,"ignoreCase":"value","enum":["PublishBuildArtifacts@1"]},{"description":"Install an SSH key prior to a build or deployment","doNotSuggest":false,"ignoreCase":"value","enum":["InstallSSHKey@0"]},{"description":"Deploy a virtual machine scale set image","doNotSuggest":false,"ignoreCase":"value","enum":["AzureVmssDeployment@0"]},{"description":"Adds tags to a build or release","doNotSuggest":false,"ignoreCase":"value","enum":["tagBuildOrRelease@0"]},{"description":"Create or update Azure App Service using Azure PowerShell","deprecationMessage":"AzureWebPowerShellDeployment is deprecated - Create or update Azure App Service using Azure PowerShell","doNotSuggest":true,"ignoreCase":"value","enum":["AzureWebPowerShellDeployment@1"]},{"description":"Deploy an Azure Cloud Service","doNotSuggest":false,"ignoreCase":"value","enum":["AzureCloudPowerShellDeployment@1"]},{"description":"Delete folders, or files matching a pattern","doNotSuggest":false,"ignoreCase":"value","enum":["DeleteFiles@1"]},{"description":"Run the gulp Node.js streaming task-based build system","doNotSuggest":false,"ignoreCase":"value","enum":["gulp@1"]},{"description":"Run the gulp Node.js streaming task-based build system","doNotSuggest":false,"ignoreCase":"value","enum":["gulp@0"]},{"description":"Run a quick web performance test in the cloud with Azure Pipelines","deprecationMessage":"QuickPerfTest is deprecated - Run a quick web performance test in the cloud with Azure Pipelines","doNotSuggest":true,"ignoreCase":"value","enum":["QuickPerfTest@1"]},{"description":"Create or update websites, web apps, virtual directories, or application pools","doNotSuggest":false,"ignoreCase":"value","enum":["IISWebAppManagementOnMachineGroup@0"]},{"description":"Install Docker CLI on agent machine.","doNotSuggest":false,"ignoreCase":"value","enum":["DockerInstaller@0"]}]},"displayName":{"type":"string","description":"Human-readable name for the task"},"name":{"type":"string","description":"ID of the task instance","pattern":"^[_A-Za-z0-9]*$"},"condition":{"type":"string","description":"Evaluate this condition expression to determine whether to run this task"},"continueOnError":{"type":"boolean","description":"Continue running the parent job even on failure?"},"enabled":{"type":"string","description":"Run this task when the job runs?"},"retryCountOnTaskFailure":{"type":"integer","description":"Number of retries if the task fails"},"timeoutInMinutes":{"type":"integer","description":"Time to wait for this task to complete before the server kills it"},"inputs":{"type":"object","description":"Task-specific inputs"},"env":{"type":"object","description":"Variables to map into the process's environment"}},"additionalProperties":false,"firstProperty":["task"],"anyOf":[{"properties":{"task":{"description":"Codesign Validation (Injected)\n\nA variant of the Codesign Validation build task that auto-runs on Production builds.","ignoreCase":"value","pattern":"^CodeSignValidationInjected@1$"},"inputs":{"description":"Codesign Validation (Injected) inputs","properties":{"Path":{"type":"string","description":"Folder to Scan","ignoreCase":"key"},"Targets":{"type":"string","description":"Targets to Scan","ignoreCase":"key"},"ToolVersion":{"description":"Tool Version","ignoreCase":"all","enum":["Latest","1.9.0","1.8.2","1.1.0"]},"CatalogPath":{"type":"string","description":"Catalog Path","ignoreCase":"key"},"PolicyType":{"description":"Policy Type","ignoreCase":"all","enum":["AzureSecurityPack","Custom"]},"PolicyFile":{"type":"string","description":"Custom Policy Path","ignoreCase":"key"},"OutputDirectory":{"type":"string","description":"Custom Output Directory","ignoreCase":"key"},"ExcludePassesFromLog":{"type":"string","description":"Exclude Passes From Log","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"PowerShell\n\nRun a PowerShell script on Linux, macOS, or Windows","ignoreCase":"value","pattern":"^PowerShell@2$"},"inputs":{"description":"PowerShell inputs","properties":{"targetType":{"description":"Type","ignoreCase":"all","enum":["filePath","inline"]},"filePath":{"type":"string","description":"Script Path","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"script":{"type":"string","description":"Script","ignoreCase":"key"},"errorActionPreference":{"description":"ErrorActionPreference","ignoreCase":"all","enum":["default","stop","continue","silentlyContinue"]},"warningPreference":{"description":"WarningPreference","ignoreCase":"all","enum":["default","stop","continue","silentlyContinue"]},"informationPreference":{"description":"InformationPreference","ignoreCase":"all","enum":["default","stop","continue","silentlyContinue"]},"verbosePreference":{"description":"VerbosePreference","ignoreCase":"all","enum":["default","stop","continue","silentlyContinue"]},"debugPreference":{"description":"DebugPreference","ignoreCase":"all","enum":["default","stop","continue","silentlyContinue"]},"failOnStderr":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"},"showWarnings":{"type":"boolean","description":"Show warnings as Azure DevOps warnings","ignoreCase":"key"},"ignoreLASTEXITCODE":{"type":"boolean","description":"Ignore $LASTEXITCODE","ignoreCase":"key"},"pwsh":{"type":"boolean","description":"Use PowerShell Core","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key"},"runScriptInSeparateScope":{"type":"boolean","description":"Run script in the separate scope","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"PowerShell\n\nRun a PowerShell script","ignoreCase":"value","pattern":"^PowerShell@1$"},"inputs":{"description":"PowerShell inputs","properties":{"scriptType":{"description":"Type","ignoreCase":"all","enum":["inlineScript","filePath"]},"scriptName":{"type":"string","description":"Script Path","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingFolder":{"type":"string","description":"Working folder","ignoreCase":"key"},"inlineScript":{"type":"string","description":"Inline Script","ignoreCase":"key"},"failOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure PowerShell\n\nRun a PowerShell script within an Azure environment","ignoreCase":"value","pattern":"^AzurePowerShell@5$"},"inputs":{"description":"Azure PowerShell inputs","properties":{"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceNameARM"]},"ScriptType":{"description":"Script Type","ignoreCase":"all","enum":["FilePath","InlineScript"]},"ScriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"Inline":{"type":"string","description":"Inline Script","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"},"errorActionPreference":{"description":"ErrorActionPreference","ignoreCase":"all","enum":["stop","continue","silentlyContinue"]},"FailOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"},"azurePowerShellVersion":{"description":"Azure PowerShell Version","ignoreCase":"all","enum":["LatestVersion","OtherVersion"],"aliases":["TargetAzurePs"]},"preferredAzurePowerShellVersion":{"type":"string","description":"Preferred Azure PowerShell Version","ignoreCase":"key","aliases":["CustomTargetAzurePs"]},"pwsh":{"type":"boolean","description":"Use PowerShell Core","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure PowerShell\n\nRun a PowerShell script within an Azure environment","ignoreCase":"value","pattern":"^AzurePowerShell@2$"},"inputs":{"description":"Azure PowerShell inputs","properties":{"azureConnectionType":{"description":"Azure Connection Type","ignoreCase":"all","enum":["ConnectedServiceName","ConnectedServiceNameARM"],"aliases":["ConnectedServiceNameSelector"]},"azureClassicSubscription":{"type":"string","description":"Azure Classic Subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceNameARM"]},"ScriptType":{"description":"Script Type","ignoreCase":"all","enum":["FilePath","InlineScript"]},"ScriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"Inline":{"type":"string","description":"Inline Script","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"},"azurePowerShellVersion":{"description":"Azure PowerShell Version","ignoreCase":"all","enum":["LatestVersion","OtherVersion"],"aliases":["TargetAzurePs"]},"preferredAzurePowerShellVersion":{"type":"string","description":"Preferred Azure PowerShell Version","ignoreCase":"key","aliases":["CustomTargetAzurePs"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure PowerShell\n\nRun a PowerShell script within an Azure environment","ignoreCase":"value","pattern":"^AzurePowerShell@3$"},"inputs":{"description":"Azure PowerShell inputs","properties":{"azureConnectionType":{"description":"Azure Connection Type","ignoreCase":"all","enum":["ConnectedServiceName","ConnectedServiceNameARM"],"aliases":["ConnectedServiceNameSelector"]},"azureClassicSubscription":{"type":"string","description":"Azure Classic Subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceNameARM"]},"ScriptType":{"description":"Script Type","ignoreCase":"all","enum":["FilePath","InlineScript"]},"ScriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"Inline":{"type":"string","description":"Inline Script","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"},"errorActionPreference":{"description":"ErrorActionPreference","ignoreCase":"all","enum":["stop","continue","silentlyContinue"]},"FailOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"},"azurePowerShellVersion":{"description":"Azure PowerShell Version","ignoreCase":"all","enum":["LatestVersion","OtherVersion"],"aliases":["TargetAzurePs"]},"preferredAzurePowerShellVersion":{"type":"string","description":"Preferred Azure PowerShell Version","ignoreCase":"key","aliases":["CustomTargetAzurePs"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure PowerShell\n\nRun a PowerShell script within an Azure environment","ignoreCase":"value","pattern":"^AzurePowerShell@4$"},"inputs":{"description":"Azure PowerShell inputs","properties":{"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceNameARM"]},"ScriptType":{"description":"Script Type","ignoreCase":"all","enum":["FilePath","InlineScript"]},"ScriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"Inline":{"type":"string","description":"Inline Script","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"},"errorActionPreference":{"description":"ErrorActionPreference","ignoreCase":"all","enum":["stop","continue","silentlyContinue"]},"FailOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"},"RestrictContextToCurrentTask":{"type":"boolean","description":"Restrict scope of context to current task","ignoreCase":"key"},"azurePowerShellVersion":{"description":"Azure PowerShell Version","ignoreCase":"all","enum":["LatestVersion","OtherVersion"],"aliases":["TargetAzurePs"]},"preferredAzurePowerShellVersion":{"type":"string","description":"Preferred Azure PowerShell Version","ignoreCase":"key","aliases":["CustomTargetAzurePs"]},"pwsh":{"type":"boolean","description":"Use PowerShell Core","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure PowerShell\n\nRun a PowerShell script within an Azure environment","ignoreCase":"value","pattern":"^AzurePowerShell@1$"},"inputs":{"description":"Azure PowerShell inputs","properties":{"ConnectedServiceNameSelector":{"description":"Azure Connection Type","ignoreCase":"all","enum":["ConnectedServiceName","ConnectedServiceNameARM"]},"ConnectedServiceName":{"type":"string","description":"Azure Classic Subscription","ignoreCase":"key"},"ConnectedServiceNameARM":{"type":"string","description":"Azure Subscription","ignoreCase":"key"},"ScriptType":{"description":"Script Type","ignoreCase":"all","enum":["FilePath","InlineScript"]},"ScriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"Inline":{"type":"string","description":"Inline Script","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MySQL database deploy\n\nRun scripts and make changes to a MySQL Database","ignoreCase":"value","pattern":"^MysqlDeploymentOnMachineGroup@1$"},"inputs":{"description":"MySQL database deploy inputs","properties":{"TaskNameSelector":{"description":"Deploy MySql Using","ignoreCase":"all","enum":["SqlTaskFile","InlineSqlTask"]},"SqlFile":{"type":"string","description":"MySQL Script","ignoreCase":"key"},"SqlInline":{"type":"string","description":"Inline MySQL Script","ignoreCase":"key"},"ServerName":{"type":"string","description":"Host Name","ignoreCase":"key"},"DatabaseName":{"type":"string","description":"Database Name","ignoreCase":"key"},"SqlUsername":{"type":"string","description":"Mysql User Name","ignoreCase":"key"},"SqlPassword":{"type":"string","description":"Password","ignoreCase":"key"},"SqlAdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":["SqlUsername","SqlPassword"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Prefast Plugin\n\nInstalls and configures the MicroBuild Prefast plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildPrefastPlugin@2$"},"inputs":{"description":"MicroBuild Prefast Plugin inputs","properties":{"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Python pip authenticate\n\nAuthentication task for the pip client used for installing Python distributions","ignoreCase":"value","pattern":"^PipAuthenticate@1$"},"inputs":{"description":"Python pip authenticate inputs","properties":{"artifactFeeds":{"type":"string","description":"My feeds (select below)","ignoreCase":"key","aliases":["artifactFeeds"]},"pythonDownloadServiceConnections":{"type":"string","description":"Feeds from external organizations","ignoreCase":"key","aliases":["pythonDownloadServiceConnections"]},"onlyAddExtraIndex":{"type":"boolean","description":"Don't set primary index URL","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Python pip authenticate\n\nAuthentication task for the pip client used for installing Python distributions","ignoreCase":"value","pattern":"^PipAuthenticate@0$"},"inputs":{"description":"Python pip authenticate inputs","properties":{"artifactFeeds":{"type":"string","description":"My feeds (select below)","ignoreCase":"key","aliases":["feedList"]},"externalFeeds":{"type":"string","description":"Feeds from external organizations","ignoreCase":"key","aliases":["externalSources"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Maven\n\nBuild, test, and deploy with Apache Maven","ignoreCase":"value","pattern":"^Maven@2$"},"inputs":{"description":"Maven inputs","properties":{"mavenPomFile":{"type":"string","description":"Maven POM file","ignoreCase":"key","aliases":["mavenPOMFile"]},"goals":{"type":"string","description":"Goal(s)","ignoreCase":"key"},"options":{"type":"string","description":"Options","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to Azure Pipelines","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test results files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"},"allowBrokenSymlinks":{"type":"boolean","description":"Allow broken symbolic links","ignoreCase":"key","aliases":["allowBrokenSymbolicLinks"]},"codeCoverageToolOption":{"description":"Code coverage tool","ignoreCase":"all","enum":["None","Cobertura","JaCoCo"],"aliases":["codeCoverageTool"]},"codeCoverageClassFilter":{"type":"string","description":"Class inclusion/exclusion filters","ignoreCase":"key","aliases":["classFilter"]},"codeCoverageClassFilesDirectories":{"type":"string","description":"Class files directories","ignoreCase":"key","aliases":["classFilesDirectories"]},"codeCoverageSourceDirectories":{"type":"string","description":"Source files directories","ignoreCase":"key","aliases":["srcDirectories"]},"codeCoverageFailIfEmpty":{"type":"boolean","description":"Fail when code coverage results are missing","ignoreCase":"key","aliases":["failIfCoverageEmpty"]},"codeCoverageRestoreOriginalPomXml":{"type":"boolean","description":"Restore original pom.xml after task execution","ignoreCase":"key","aliases":["restoreOriginalPomXml"]},"javaHomeOption":{"description":"Set JAVA_HOME by","ignoreCase":"all","enum":["JDKVersion","Path"],"aliases":["javaHomeSelection"]},"jdkVersionOption":{"description":"JDK version","ignoreCase":"all","enum":["default","1.11","1.10","1.9","1.8","1.7","1.6"],"aliases":["jdkVersion"]},"jdkDirectory":{"type":"string","description":"JDK path","ignoreCase":"key","aliases":["jdkUserInputPath"]},"jdkArchitectureOption":{"description":"JDK architecture","ignoreCase":"all","enum":["x86","x64"],"aliases":["jdkArchitecture"]},"mavenVersionOption":{"description":"Maven version","ignoreCase":"all","enum":["Default","Path"],"aliases":["mavenVersionSelection"]},"mavenDirectory":{"type":"string","description":"Maven path","ignoreCase":"key","aliases":["mavenPath"]},"mavenSetM2Home":{"type":"boolean","description":"Set M2_HOME variable","ignoreCase":"key"},"mavenOptions":{"type":"string","description":"Set MAVEN_OPTS to","ignoreCase":"key","aliases":["mavenOpts"]},"mavenAuthenticateFeed":{"type":"boolean","description":"Authenticate built-in Maven feeds","ignoreCase":"key","aliases":["mavenFeedAuthenticate"]},"sonarQubeRunAnalysis":{"type":"boolean","description":"Run SonarQube or SonarCloud analysis","ignoreCase":"key","aliases":["sqAnalysisEnabled"]},"isJacocoCoverageReportXML":{"type":"boolean","description":"Use XML Jacoco reports for SonarQube analysis","ignoreCase":"key"},"sqMavenPluginVersionChoice":{"description":"SonarQube scanner for Maven version","ignoreCase":"all","enum":["latest","pom"]},"checkStyleRunAnalysis":{"type":"boolean","description":"Run Checkstyle","ignoreCase":"key","aliases":["checkstyleAnalysisEnabled"]},"pmdRunAnalysis":{"type":"boolean","description":"Run PMD","ignoreCase":"key","aliases":["pmdAnalysisEnabled"]},"findBugsRunAnalysis":{"type":"boolean","description":"Run FindBugs","ignoreCase":"key","aliases":["findbugsAnalysisEnabled"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Maven\n\nBuild, test, and deploy with Apache Maven","ignoreCase":"value","pattern":"^Maven@3$"},"inputs":{"description":"Maven inputs","properties":{"mavenPomFile":{"type":"string","description":"Maven POM file","ignoreCase":"key","aliases":["mavenPOMFile"]},"goals":{"type":"string","description":"Goal(s)","ignoreCase":"key"},"options":{"type":"string","description":"Options","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to Azure Pipelines","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test results files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"},"allowBrokenSymlinks":{"type":"boolean","description":"Allow broken symbolic links","ignoreCase":"key","aliases":["allowBrokenSymbolicLinks"]},"codeCoverageToolOption":{"description":"Code coverage tool","ignoreCase":"all","enum":["None","Cobertura","JaCoCo"],"aliases":["codeCoverageTool"]},"codeCoverageClassFilter":{"type":"string","description":"Class inclusion/exclusion filters","ignoreCase":"key","aliases":["classFilter"]},"codeCoverageClassFilesDirectories":{"type":"string","description":"Class files directories","ignoreCase":"key","aliases":["classFilesDirectories"]},"codeCoverageSourceDirectories":{"type":"string","description":"Source files directories","ignoreCase":"key","aliases":["srcDirectories"]},"codeCoverageFailIfEmpty":{"type":"boolean","description":"Fail when code coverage results are missing","ignoreCase":"key","aliases":["failIfCoverageEmpty"]},"codeCoverageRestoreOriginalPomXml":{"type":"boolean","description":"Restore original pom.xml after task execution","ignoreCase":"key","aliases":["restoreOriginalPomXml"]},"javaHomeOption":{"description":"Set JAVA_HOME by","ignoreCase":"all","enum":["JDKVersion","Path"],"aliases":["javaHomeSelection"]},"jdkVersionOption":{"description":"JDK version","ignoreCase":"all","enum":["default","1.11","1.10","1.9","1.8","1.7","1.6"],"aliases":["jdkVersion"]},"jdkDirectory":{"type":"string","description":"JDK path","ignoreCase":"key","aliases":["jdkUserInputPath"]},"jdkArchitectureOption":{"description":"JDK architecture","ignoreCase":"all","enum":["x86","x64"],"aliases":["jdkArchitecture"]},"mavenVersionOption":{"description":"Maven version","ignoreCase":"all","enum":["Default","Path"],"aliases":["mavenVersionSelection"]},"mavenDirectory":{"type":"string","description":"Maven path","ignoreCase":"key","aliases":["mavenPath"]},"mavenSetM2Home":{"type":"boolean","description":"Set M2_HOME variable","ignoreCase":"key"},"mavenOptions":{"type":"string","description":"Set MAVEN_OPTS to","ignoreCase":"key","aliases":["mavenOpts"]},"mavenAuthenticateFeed":{"type":"boolean","description":"Authenticate built-in Maven feeds","ignoreCase":"key","aliases":["mavenFeedAuthenticate"]},"effectivePomSkip":{"type":"boolean","description":"Skip generating effective POM while authenticating built-in feeds","ignoreCase":"key","aliases":["skipEffectivePom"]},"sonarQubeRunAnalysis":{"type":"boolean","description":"Run SonarQube or SonarCloud analysis","ignoreCase":"key","aliases":["sqAnalysisEnabled"]},"isJacocoCoverageReportXML":{"type":"boolean","description":"Use XML Jacoco reports for SonarQube analysis","ignoreCase":"key"},"sqMavenPluginVersionChoice":{"description":"SonarQube scanner for Maven version","ignoreCase":"all","enum":["latest","pom"]},"checkStyleRunAnalysis":{"type":"boolean","description":"Run Checkstyle","ignoreCase":"key","aliases":["checkstyleAnalysisEnabled"]},"pmdRunAnalysis":{"type":"boolean","description":"Run PMD","ignoreCase":"key","aliases":["pmdAnalysisEnabled"]},"findBugsRunAnalysis":{"type":"boolean","description":"Run FindBugs","ignoreCase":"key","aliases":["findbugsAnalysisEnabled"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Maven\n\nBuild with Apache Maven","ignoreCase":"value","pattern":"^Maven@1$"},"inputs":{"description":"Maven inputs","properties":{"mavenPomFile":{"type":"string","description":"Maven POM file","ignoreCase":"key","aliases":["mavenPOMFile"]},"goals":{"type":"string","description":"Goal(s)","ignoreCase":"key"},"options":{"type":"string","description":"Options","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to TFS/Team Services","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test Results Files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test Run Title","ignoreCase":"key"},"codeCoverageToolOption":{"description":"Code Coverage Tool","ignoreCase":"all","enum":["None","Cobertura","JaCoCo"],"aliases":["codeCoverageTool"]},"codeCoverageClassFilter":{"type":"string","description":"Class Inclusion/Exclusion Filters","ignoreCase":"key","aliases":["classFilter"]},"codeCoverageClassFilesDirectories":{"type":"string","description":"Class Files Directories","ignoreCase":"key","aliases":["classFilesDirectories"]},"codeCoverageSourceDirectories":{"type":"string","description":"Source Files Directories","ignoreCase":"key","aliases":["srcDirectories"]},"codeCoverageFailIfEmpty":{"type":"boolean","description":"Fail When Code Coverage Results Are Missing","ignoreCase":"key","aliases":["failIfCoverageEmpty"]},"javaHomeOption":{"description":"Set JAVA_HOME by","ignoreCase":"all","enum":["JDKVersion","Path"],"aliases":["javaHomeSelection"]},"jdkVersionOption":{"description":"JDK Version","ignoreCase":"all","enum":["default","1.9","1.8","1.7","1.6"],"aliases":["jdkVersion"]},"jdkDirectory":{"type":"string","description":"JDK Path","ignoreCase":"key","aliases":["jdkUserInputPath"]},"jdkArchitectureOption":{"description":"JDK Architecture","ignoreCase":"all","enum":["x86","x64"],"aliases":["jdkArchitecture"]},"mavenVersionOption":{"description":"Maven Version","ignoreCase":"all","enum":["Default","Path"],"aliases":["mavenVersionSelection"]},"mavenDirectory":{"type":"string","description":"Maven Path","ignoreCase":"key","aliases":["mavenPath"]},"mavenSetM2Home":{"type":"boolean","description":"Set M2_HOME variable","ignoreCase":"key"},"mavenOptions":{"type":"string","description":"Set MAVEN_OPTS to","ignoreCase":"key","aliases":["mavenOpts"]},"mavenAuthenticateFeed":{"type":"boolean","description":"Authenticate built-in Maven feeds","ignoreCase":"key","aliases":["mavenFeedAuthenticate"]},"sonarQubeRunAnalysis":{"type":"boolean","description":"Run SonarQube Analysis","ignoreCase":"key","aliases":["sqAnalysisEnabled"]},"sonarQubeServiceEndpoint":{"type":"string","description":"SonarQube Endpoint","ignoreCase":"key","aliases":["sqConnectedServiceName"]},"sonarQubeProjectName":{"type":"string","description":"SonarQube Project Name","ignoreCase":"key","aliases":["sqProjectName"]},"sonarQubeProjectKey":{"type":"string","description":"SonarQube Project Key","ignoreCase":"key","aliases":["sqProjectKey"]},"sonarQubeProjectVersion":{"type":"string","description":"SonarQube Project Version","ignoreCase":"key","aliases":["sqProjectVersion"]},"sonarQubeSpecifyDB":{"type":"boolean","description":"The SonarQube server version is lower than 5.2","ignoreCase":"key","aliases":["sqDbDetailsRequired"]},"sonarQubeDBUrl":{"type":"string","description":"Db Connection String","ignoreCase":"key","aliases":["sqDbUrl"]},"sonarQubeDBUsername":{"type":"string","description":"Db Username","ignoreCase":"key","aliases":["sqDbUsername"]},"sonarQubeDBPassword":{"type":"string","description":"Db User Password","ignoreCase":"key","aliases":["sqDbPassword"]},"sonarQubeIncludeFullReport":{"type":"boolean","description":"Include full analysis report in the build summary (SQ 5.3+)","ignoreCase":"key","aliases":["sqAnalysisIncludeFullReport"]},"sonarQubeFailWhenQualityGateFails":{"type":"boolean","description":"Fail the build on quality gate failure (SQ 5.3+)","ignoreCase":"key","aliases":["sqAnalysisBreakBuildIfQualityGateFailed"]},"checkStyleRunAnalysis":{"type":"boolean","description":"Run Checkstyle","ignoreCase":"key","aliases":["checkstyleAnalysisEnabled"]},"pmdRunAnalysis":{"type":"boolean","description":"Run PMD","ignoreCase":"key","aliases":["pmdAnalysisEnabled"]},"findBugsRunAnalysis":{"type":"boolean","description":"Run FindBugs","ignoreCase":"key","aliases":["findbugsAnalysisEnabled"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Zip A Folder\n\nZip Files and Folder","ignoreCase":"value","pattern":"^zip@0$"},"inputs":{"description":"Zip A Folder inputs","properties":{"pathToZipFolder":{"type":"string","description":"Path to folder","ignoreCase":"key"},"pathToZipFile":{"type":"string","description":"Path to the zip file","ignoreCase":"key"},"overwrite":{"type":"boolean","description":"Overwrite zip file","ignoreCase":"key"}},"additionalProperties":false,"required":["pathToZipFolder","pathToZipFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Publish Symbols to Artifact Services-preview\n\nPublish Symbols to Artifact Services - Internal Preview","ignoreCase":"value","pattern":"^artifactSymbolTask@0$"},"inputs":{"description":"Publish Symbols to Artifact Services-preview inputs","properties":{"symbolServiceURI":{"type":"string","description":"Symbol Service Endpoint","ignoreCase":"key"},"requestName":{"type":"string","description":"Symbol Request Name","ignoreCase":"key"},"sourcePath":{"type":"string","description":"Upload Source Root Path","ignoreCase":"key"},"assemblyPath":{"type":"string","description":"Override path to symbol assemblies","ignoreCase":"key"},"toLowerCase":{"type":"boolean","description":"Lowercase symbol request name","ignoreCase":"key"},"detailedLog":{"type":"boolean","description":"Verbose Logging","ignoreCase":"key"},"expirationInDays":{"type":"string","description":"Expiration (in days)","ignoreCase":"key"},"usePat":{"type":"boolean","description":"Use Personal Access Token","ignoreCase":"key"},"append":{"type":"boolean","description":"Allow appending to existing request","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Rollback PowerShell\n\nRun a powershell script to rollback deployments. Task execution context is available in the powershell context for implementing conditional rollback","ignoreCase":"value","pattern":"^Rollback@1$"},"inputs":{"description":"Rollback PowerShell inputs","properties":{"type":{"description":"Type","ignoreCase":"all","enum":["InlineScript","FilePath"]},"rollbackpowershellfile":{"type":"string","description":"Script Path","ignoreCase":"key"},"additionalarguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"},"workingFolder":{"type":"string","description":"Working folder","ignoreCase":"key"},"script":{"type":"string","description":"Script","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":".NET Core\n\nBuild, test, package, or publish a dotnet application, or run a custom dotnet command","ignoreCase":"value","pattern":"^DotNetCoreCLI@2$"},"inputs":{"description":".NET Core inputs","properties":{"command":{"description":"Command","ignoreCase":"all","enum":["build","push","pack","publish","restore","run","test","custom"]},"publishWebProjects":{"type":"boolean","description":"Publish web projects","ignoreCase":"key"},"projects":{"type":"string","description":"Path to project(s)","ignoreCase":"key"},"custom":{"type":"string","description":"Custom command","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"restoreArguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"publishTestResults":{"type":"boolean","description":"Publish test results and code coverage","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"},"zipAfterPublish":{"type":"boolean","description":"Zip published projects","ignoreCase":"key"},"modifyOutputPath":{"type":"boolean","description":"Add project's folder name to publish path","ignoreCase":"key"},"feedsToUse":{"description":"Feeds to use","ignoreCase":"all","enum":["select","config"],"aliases":["selectOrConfig"]},"vstsFeed":{"type":"string","description":"Use packages from this Azure Artifacts feed","ignoreCase":"key","aliases":["feedRestore"]},"includeNuGetOrg":{"type":"boolean","description":"Use packages from NuGet.org","ignoreCase":"key"},"nugetConfigPath":{"type":"string","description":"Path to NuGet.config","ignoreCase":"key"},"externalFeedCredentials":{"type":"string","description":"Credentials for feeds outside this organization/collection","ignoreCase":"key","aliases":["externalEndpoints"]},"noCache":{"type":"boolean","description":"Disable local cache","ignoreCase":"key"},"restoreDirectory":{"type":"string","description":"Destination directory","ignoreCase":"key","aliases":["packagesDirectory"]},"verbosityRestore":{"description":"Verbosity","ignoreCase":"all","enum":["-","Quiet","Minimal","Normal","Detailed","Diagnostic"]},"packagesToPush":{"type":"string","description":"Path to NuGet package(s) to publish","ignoreCase":"key","aliases":["searchPatternPush"]},"nuGetFeedType":{"description":"Target feed location","ignoreCase":"all","enum":["internal","external"]},"publishVstsFeed":{"type":"string","description":"Target feed","ignoreCase":"key","aliases":["feedPublish"]},"publishPackageMetadata":{"type":"boolean","description":"Publish pipeline metadata","ignoreCase":"key"},"publishFeedCredentials":{"type":"string","description":"NuGet server","ignoreCase":"key","aliases":["externalEndpoint"]},"packagesToPack":{"type":"string","description":"Path to csproj or nuspec file(s) to pack","ignoreCase":"key","aliases":["searchPatternPack"]},"configuration":{"type":"string","description":"Configuration to Package","ignoreCase":"key","aliases":["configurationToPack"]},"packDirectory":{"type":"string","description":"Package Folder","ignoreCase":"key","aliases":["outputDir"]},"nobuild":{"type":"boolean","description":"Do not build","ignoreCase":"key"},"includesymbols":{"type":"boolean","description":"Include Symbols","ignoreCase":"key"},"includesource":{"type":"boolean","description":"Include Source","ignoreCase":"key"},"versioningScheme":{"description":"Automatic package versioning","ignoreCase":"all","enum":["off","byPrereleaseNumber","byEnvVar","byBuildNumber"]},"versionEnvVar":{"type":"string","description":"Environment variable","ignoreCase":"key"},"majorVersion":{"type":"string","description":"Major","ignoreCase":"key","aliases":["requestedMajorVersion"]},"minorVersion":{"type":"string","description":"Minor","ignoreCase":"key","aliases":["requestedMinorVersion"]},"patchVersion":{"type":"string","description":"Patch","ignoreCase":"key","aliases":["requestedPatchVersion"]},"buildProperties":{"type":"string","description":"Additional build properties","ignoreCase":"key"},"verbosityPack":{"description":"Verbosity","ignoreCase":"all","enum":["-","Quiet","Minimal","Normal","Detailed","Diagnostic"]},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":".NET Core (PREVIEW)\n\nBuild, test and publish using dotnet core command-line.","ignoreCase":"value","pattern":"^DotNetCoreCLI@0$"},"inputs":{"description":".NET Core (PREVIEW) inputs","properties":{"command":{"description":"Command","ignoreCase":"all","enum":["build","publish","restore","test","run"]},"publishWebProjects":{"type":"boolean","description":"Publish Web Projects","ignoreCase":"key"},"projects":{"type":"string","description":"Project(s)","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"zipAfterPublish":{"type":"boolean","description":"Zip Published Projects","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"deprecationMessage":"DotNetCoreCLI is deprecated - Build, test and publish using dotnet core command-line.","doNotSuggest":true,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":".NET Core\n\nBuild, test and publish using dotnet core command-line.","ignoreCase":"value","pattern":"^DotNetCoreCLI@1$"},"inputs":{"description":".NET Core inputs","properties":{"command":{"description":"Command","ignoreCase":"all","enum":["build","publish","restore","test","run"]},"publishWebProjects":{"type":"boolean","description":"Publish Web Projects","ignoreCase":"key"},"projects":{"type":"string","description":"Project(s)","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"zipAfterPublish":{"type":"boolean","description":"Zip Published Projects","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Tokenize File\n\nTokenizes a file.","ignoreCase":"value","pattern":"^JSONTokenizer@1$"},"inputs":{"description":"Tokenize File inputs","properties":{"sourcePath":{"type":"string","description":"Source Path","ignoreCase":"key"},"filePattern":{"type":"string","description":"File Pattern","ignoreCase":"key"},"tokenizeType":{"description":"Tokenize Type","ignoreCase":"all","enum":["Json"]},"includes":{"type":"string","description":"Includes","ignoreCase":"key"},"excludes":{"type":"string","description":"Excludes","ignoreCase":"key"},"nullBehavior":{"description":"Null Behavior","ignoreCase":"all","enum":["warning","error"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Send Helix Start Telemetry\n\nSend start job telemetry for .NET Core builds","ignoreCase":"value","pattern":"^SendStartTelemetry@0$"},"inputs":{"description":"Send Helix Start Telemetry inputs","properties":{"helixRepo":{"type":"string","description":"[organization name]/[repository name]","ignoreCase":"key"},"helixType":{"type":"string","description":"telemetry type","ignoreCase":"key"},"maxRetries":{"type":"string","description":"Maximum number of retry attempts","ignoreCase":"key"},"retryDelay":{"type":"string","description":"Number of seconds to wait between retry attempts","ignoreCase":"key"},"runAsPublic":{"type":"boolean","description":"Always send telemetry as public","ignoreCase":"key"},"buildConfig":{"type":"string","description":"Build configuration","ignoreCase":"key"}},"additionalProperties":false,"required":["helixRepo"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Xamarin Component Restore\n\nThis task is deprecated. Use 'NuGet' instead.","ignoreCase":"value","pattern":"^XamarinComponentRestore@0$"},"inputs":{"description":"Xamarin Component Restore inputs","properties":{"solutionFile":{"type":"string","description":"Path to solution","ignoreCase":"key","aliases":["solution"]},"email":{"type":"string","description":"Email","ignoreCase":"key"},"password":{"type":"string","description":"Password","ignoreCase":"key"}},"additionalProperties":false,"required":["email","password"]}},"deprecationMessage":"XamarinComponentRestore is deprecated - This task is deprecated. Use 'NuGet' instead.","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"ReportGenerator\n\nReportGenerator converts coverage reports generated by coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover, gcov or lcov into human readable reports in various formats.","ignoreCase":"value","pattern":"^reportgenerator@5$"},"inputs":{"description":"ReportGenerator inputs","properties":{"reports":{"type":"string","description":"Reports","ignoreCase":"key"},"targetdir":{"type":"string","description":"Target directory","ignoreCase":"key"},"reporttypes":{"type":"string","description":"Report types","ignoreCase":"key"},"sourcedirs":{"type":"string","description":"Source directories","ignoreCase":"key"},"historydir":{"type":"string","description":"History directory","ignoreCase":"key"},"plugins":{"type":"string","description":"Plugins","ignoreCase":"key"},"assemblyfilters":{"type":"string","description":"Assembly filters","ignoreCase":"key"},"classfilters":{"type":"string","description":"Class filters","ignoreCase":"key"},"filefilters":{"type":"string","description":"File filters","ignoreCase":"key"},"verbosity":{"description":"Verbosity","ignoreCase":"all","enum":["Verbose","Info","Warning","Error","Off"]},"title":{"type":"string","description":"Title","ignoreCase":"key"},"tag":{"type":"string","description":"Tag","ignoreCase":"key"},"customSettings":{"type":"string","description":"Custom settings","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"ReportGenerator\n\nReportGenerator converts coverage reports generated by coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover, gcov or lcov into human readable reports in various formats.","ignoreCase":"value","pattern":"^reportgenerator@4$"},"inputs":{"description":"ReportGenerator inputs","properties":{"reports":{"type":"string","description":"Reports","ignoreCase":"key"},"targetdir":{"type":"string","description":"Target directory","ignoreCase":"key"},"reporttypes":{"type":"string","description":"Report types","ignoreCase":"key"},"sourcedirs":{"type":"string","description":"Source directories","ignoreCase":"key"},"historydir":{"type":"string","description":"History directory","ignoreCase":"key"},"plugins":{"type":"string","description":"Plugins","ignoreCase":"key"},"assemblyfilters":{"type":"string","description":"Assembly filters","ignoreCase":"key"},"classfilters":{"type":"string","description":"Class filters","ignoreCase":"key"},"filefilters":{"type":"string","description":"File filters","ignoreCase":"key"},"verbosity":{"description":"Verbosity","ignoreCase":"all","enum":["Verbose","Info","Warning","Error","Off"]},"title":{"type":"string","description":"Title","ignoreCase":"key"},"tag":{"type":"string","description":"Tag","ignoreCase":"key"},"customSettings":{"type":"string","description":"Custom settings","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure App Service Deploy\n\nUpdate Azure App Service using Web Deploy / Kudu REST APIs","ignoreCase":"value","pattern":"^AzureRmWebAppDeployment@2$"},"inputs":{"description":"Azure App Service Deploy inputs","properties":{"ConnectedServiceName":{"type":"string","description":"Azure Subscription","ignoreCase":"key"},"WebAppName":{"type":"string","description":"App Service name","ignoreCase":"key"},"DeployToSlotFlag":{"type":"boolean","description":"Deploy to slot","ignoreCase":"key"},"ResourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"SlotName":{"type":"string","description":"Slot","ignoreCase":"key"},"VirtualApplication":{"type":"string","description":"Virtual Application","ignoreCase":"key"},"Package":{"type":"string","description":"Package or Folder","ignoreCase":"key"},"WebAppUri":{"type":"string","description":"App Service URL","ignoreCase":"key"},"UseWebDeploy":{"type":"boolean","description":"Publish using Web Deploy","ignoreCase":"key"},"SetParametersFile":{"type":"string","description":"SetParameters File","ignoreCase":"key"},"RemoveAdditionalFilesFlag":{"type":"boolean","description":"Remove Additional Files at Destination","ignoreCase":"key"},"ExcludeFilesFromAppDataFlag":{"type":"boolean","description":"Exclude Files from the App_Data Folder","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"},"TakeAppOfflineFlag":{"type":"boolean","description":"Take App Offline","ignoreCase":"key"}},"additionalProperties":false,"required":["ConnectedServiceName","WebAppName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure App Service deploy\n\nDeploy to Azure App Service a web, mobile, or API app using Docker, Java, .NET, .NET Core, Node.js, PHP, Python, or Ruby","ignoreCase":"value","pattern":"^AzureRmWebAppDeployment@3$"},"inputs":{"description":"Azure App Service deploy inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"appType":{"description":"App type","ignoreCase":"all","enum":["app","applinux","functionapp","api","mobileapp"],"aliases":["WebAppKind"]},"WebAppName":{"type":"string","description":"App Service name","ignoreCase":"key"},"DeployToSlotFlag":{"type":"boolean","description":"Deploy to slot","ignoreCase":"key"},"ResourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"SlotName":{"type":"string","description":"Slot","ignoreCase":"key"},"ImageSource":{"description":"Image Source","ignoreCase":"all","enum":["Registry","Builtin"]},"AzureContainerRegistry":{"type":"string","description":"Registry","ignoreCase":"key"},"AzureContainerRegistryLoginServer":{"type":"string","description":"Registry Login Server Name","ignoreCase":"key"},"AzureContainerRegistryImage":{"type":"string","description":"Image","ignoreCase":"key"},"AzureContainerRegistryTag":{"type":"string","description":"Tag","ignoreCase":"key"},"DockerRepositoryAccess":{"description":"Repository Access","ignoreCase":"all","enum":["private","public"]},"dockerRegistryConnection":{"type":"string","description":"Registry Connection","ignoreCase":"key","aliases":["RegistryConnectedServiceName"]},"PrivateRegistryImage":{"type":"string","description":"Image","ignoreCase":"key"},"PrivateRegistryTag":{"type":"string","description":"Tag","ignoreCase":"key"},"DockerNamespace":{"type":"string","description":"Registry or Namespace","ignoreCase":"key"},"DockerRepository":{"type":"string","description":"Image","ignoreCase":"key"},"DockerImageTag":{"type":"string","description":"Tag","ignoreCase":"key"},"VirtualApplication":{"type":"string","description":"Virtual application","ignoreCase":"key"},"Package":{"type":"string","description":"Package or folder","ignoreCase":"key"},"packageForLinux":{"type":"string","description":"Package or folder","ignoreCase":"key","aliases":["BuiltinLinuxPackage"]},"RuntimeStack":{"type":"string","description":"Runtime Stack","ignoreCase":"key"},"StartupCommand":{"type":"string","description":"Startup command ","ignoreCase":"key"},"WebAppUri":{"type":"string","description":"App Service URL","ignoreCase":"key"},"ScriptType":{"description":"Deployment script type","ignoreCase":"all","enum":["","Inline Script","File Path"]},"InlineScript":{"type":"string","description":"Inline Script","ignoreCase":"key"},"ScriptPath":{"type":"string","description":"Deployment script path","ignoreCase":"key"},"GenerateWebConfig":{"type":"boolean","description":"Generate Web.config","ignoreCase":"key"},"WebConfigParameters":{"type":"string","description":"Web.config parameters","ignoreCase":"key"},"AppSettings":{"type":"string","description":"App settings","ignoreCase":"key"},"ConfigurationSettings":{"type":"string","description":"Configuration settings","ignoreCase":"key"},"TakeAppOfflineFlag":{"type":"boolean","description":"Take App Offline","ignoreCase":"key"},"UseWebDeploy":{"type":"boolean","description":"Publish using Web Deploy","ignoreCase":"key"},"SetParametersFile":{"type":"string","description":"SetParameters file","ignoreCase":"key"},"RemoveAdditionalFilesFlag":{"type":"boolean","description":"Remove additional files at destination","ignoreCase":"key"},"ExcludeFilesFromAppDataFlag":{"type":"boolean","description":"Exclude files from the App_Data folder","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional arguments","ignoreCase":"key"},"RenameFilesFlag":{"type":"boolean","description":"Rename locked files","ignoreCase":"key"},"enableXmlTransform":{"type":"boolean","description":"XML transformation","ignoreCase":"key","aliases":["XmlTransformation"]},"enableXmlVariableSubstitution":{"type":"boolean","description":"XML variable substitution","ignoreCase":"key","aliases":["XmlVariableSubstitution"]},"JSONFiles":{"type":"string","description":"JSON variable substitution","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","WebAppName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure App Service deploy\n\nDeploy to Azure App Service a web, mobile, or API app using Docker, Java, .NET, .NET Core, Node.js, PHP, Python, or Ruby","ignoreCase":"value","pattern":"^AzureRmWebAppDeployment@4$"},"inputs":{"description":"Azure App Service deploy inputs","properties":{"ConnectionType":{"description":"Connection type","ignoreCase":"all","enum":["AzureRM","PublishProfile"]},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"PublishProfilePath":{"type":"string","description":"Publish profile path","ignoreCase":"key"},"PublishProfilePassword":{"type":"string","description":"Publish profile password","ignoreCase":"key"},"appType":{"description":"App Service type","ignoreCase":"all","enum":["webApp","webAppLinux","webAppContainer","functionApp","functionAppLinux","functionAppContainer","apiApp","mobileApp"],"aliases":["WebAppKind"]},"WebAppName":{"type":"string","description":"App Service name","ignoreCase":"key"},"deployToSlotOrASE":{"type":"boolean","description":"Deploy to Slot or App Service Environment","ignoreCase":"key","aliases":["DeployToSlotOrASEFlag"]},"ResourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"SlotName":{"type":"string","description":"Slot","ignoreCase":"key"},"DockerNamespace":{"type":"string","description":"Registry or Namespace","ignoreCase":"key"},"DockerRepository":{"type":"string","description":"Image","ignoreCase":"key"},"DockerImageTag":{"type":"string","description":"Tag","ignoreCase":"key"},"VirtualApplication":{"type":"string","description":"Virtual application","ignoreCase":"key"},"packageForLinux":{"type":"string","description":"Package or folder","ignoreCase":"key","aliases":["Package"]},"RuntimeStack":{"type":"string","description":"Runtime Stack","ignoreCase":"key"},"RuntimeStackFunction":{"description":"Runtime Stack","ignoreCase":"all","enum":["DOTNET|2.2","DOTNET|3.1","JAVA|8","JAVA|11","NODE|8","NODE|10","NODE|12","NODE|14","PYTHON|3.6","PYTHON|3.7","PYTHON|3.8"]},"StartupCommand":{"type":"string","description":"Startup command ","ignoreCase":"key"},"ScriptType":{"description":"Deployment script type","ignoreCase":"all","enum":["","Inline Script","File Path"]},"InlineScript":{"type":"string","description":"Inline Script","ignoreCase":"key"},"ScriptPath":{"type":"string","description":"Deployment script path","ignoreCase":"key"},"WebConfigParameters":{"type":"string","description":"Generate web.config parameters for Python, Node.js, Go and Java apps","ignoreCase":"key"},"AppSettings":{"type":"string","description":"App settings","ignoreCase":"key"},"ConfigurationSettings":{"type":"string","description":"Configuration settings","ignoreCase":"key"},"enableCustomDeployment":{"type":"boolean","description":"Select deployment method","ignoreCase":"key","aliases":["UseWebDeploy"]},"DeploymentType":{"description":"Deployment method","ignoreCase":"all","enum":["webDeploy","zipDeploy","runFromZip"]},"TakeAppOfflineFlag":{"type":"boolean","description":"Take App Offline","ignoreCase":"key"},"SetParametersFile":{"type":"string","description":"SetParameters file","ignoreCase":"key"},"RemoveAdditionalFilesFlag":{"type":"boolean","description":"Remove additional files at destination","ignoreCase":"key"},"ExcludeFilesFromAppDataFlag":{"type":"boolean","description":"Exclude files from the App_Data folder","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional arguments","ignoreCase":"key"},"RenameFilesFlag":{"type":"boolean","description":"Rename locked files","ignoreCase":"key"},"enableXmlTransform":{"type":"boolean","description":"XML transformation","ignoreCase":"key","aliases":["XmlTransformation"]},"enableXmlVariableSubstitution":{"type":"boolean","description":"XML variable substitution","ignoreCase":"key","aliases":["XmlVariableSubstitution"]},"JSONFiles":{"type":"string","description":"JSON variable substitution","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"PowerShell on Target Machines\n\nExecute PowerShell scripts on remote machine(s)","ignoreCase":"value","pattern":"^PowerShellOnTargetMachines@1$"},"inputs":{"description":"PowerShell on Target Machines inputs","properties":{"EnvironmentName":{"type":"string","description":"Machines","ignoreCase":"key"},"AdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"AdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"Protocol":{"description":"Protocol","ignoreCase":"all","enum":["Http","Https"]},"TestCertificate":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"},"ScriptPath":{"type":"string","description":"PowerShell Script","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"},"InitializationScriptPath":{"type":"string","description":"Initialization Script","ignoreCase":"key"},"SessionVariables":{"type":"string","description":"Session Variables","ignoreCase":"key"},"RunPowershellInParallel":{"type":"boolean","description":"Run PowerShell in Parallel","ignoreCase":"key"},"ResourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"MachineNames":{"type":"string","description":"Filter Criteria","ignoreCase":"key"}},"additionalProperties":false,"required":["EnvironmentName","ScriptPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"PowerShell on target machines\n\nExecute PowerShell scripts on remote machines using PSSession and Invoke-Command for remoting","ignoreCase":"value","pattern":"^PowerShellOnTargetMachines@3$"},"inputs":{"description":"PowerShell on target machines inputs","properties":{"Machines":{"type":"string","description":"Machines","ignoreCase":"key"},"UserName":{"type":"string","description":"Username","ignoreCase":"key"},"UserPassword":{"type":"string","description":"Password","ignoreCase":"key"},"ScriptType":{"description":"Script Type","ignoreCase":"all","enum":["FilePath","Inline"]},"ScriptPath":{"type":"string","description":"Script File Path","ignoreCase":"key"},"InlineScript":{"type":"string","description":"Script","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"},"InitializationScript":{"type":"string","description":"Initialization script","ignoreCase":"key"},"SessionVariables":{"type":"string","description":"Session Variables","ignoreCase":"key"},"CommunicationProtocol":{"description":"Protocol","ignoreCase":"all","enum":["Http","Https"]},"AuthenticationMechanism":{"description":"Authentication","ignoreCase":"all","enum":["Default","Credssp"]},"NewPsSessionOptionArguments":{"type":"string","description":"Session Option parameters","ignoreCase":"key"},"ErrorActionPreference":{"description":"ErrorActionPreference","ignoreCase":"all","enum":["stop","continue","silentlyContinue"]},"failOnStderr":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"},"ignoreLASTEXITCODE":{"type":"boolean","description":"Ignore $LASTEXITCODE","ignoreCase":"key"},"WorkingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key"},"RunPowershellInParallel":{"type":"boolean","description":"Run PowerShell in Parallel","ignoreCase":"key"}},"additionalProperties":false,"required":["Machines"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"PowerShell on Target Machines\n\nExecute PowerShell scripts on remote machine(s)","ignoreCase":"value","pattern":"^PowerShellOnTargetMachines@2$"},"inputs":{"description":"PowerShell on Target Machines inputs","properties":{"EnvironmentName":{"type":"string","description":"Machines","ignoreCase":"key"},"AdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"AdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"Protocol":{"description":"Protocol","ignoreCase":"all","enum":["Http","Https"]},"TestCertificate":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"},"ScriptPath":{"type":"string","description":"PowerShell Script","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"},"InitializationScriptPath":{"type":"string","description":"Initialization Script","ignoreCase":"key"},"SessionVariables":{"type":"string","description":"Session Variables","ignoreCase":"key"},"RunPowershellInParallel":{"type":"boolean","description":"Run PowerShell in Parallel","ignoreCase":"key"},"ResourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"MachineNames":{"type":"string","description":"Filter Criteria","ignoreCase":"key"}},"additionalProperties":false,"required":["EnvironmentName","ScriptPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Publish code coverage results\n\nPublish Cobertura or JaCoCo code coverage results from a build","ignoreCase":"value","pattern":"^PublishCodeCoverageResults@1$"},"inputs":{"description":"Publish code coverage results inputs","properties":{"codeCoverageTool":{"description":"Code coverage tool","ignoreCase":"all","enum":["Cobertura","JaCoCo"]},"summaryFileLocation":{"type":"string","description":"Summary file","ignoreCase":"key"},"pathToSources":{"type":"string","description":"Path to Source files","ignoreCase":"key"},"reportDirectory":{"type":"string","description":"Report directory","ignoreCase":"key"},"additionalCodeCoverageFiles":{"type":"string","description":"Additional files","ignoreCase":"key"},"failIfCoverageEmpty":{"type":"boolean","description":"Fail when code coverage results are missing","ignoreCase":"key"}},"additionalProperties":false,"required":["summaryFileLocation"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Run functional tests\n\nDeprecated: This task and it’s companion task (Visual Studio Test Agent Deployment) are deprecated. Use the 'Visual Studio Test' task instead. The VSTest task can run unit as well as functional tests. Run tests on one or more agents using the multi-agent job setting. Use the 'Visual Studio Test Platform' task to run tests without needing Visual Studio on the agent. VSTest task also brings new capabilities such as automatically rerunning failed tests.","ignoreCase":"value","pattern":"^RunVisualStudioTestsusingTestAgent@1$"},"inputs":{"description":"Run functional tests inputs","properties":{"testMachineGroup":{"type":"string","description":"Machines","ignoreCase":"key"},"dropLocation":{"type":"string","description":"Test Drop Location","ignoreCase":"key"},"testSelection":{"description":"Test Selection","ignoreCase":"all","enum":["testAssembly","testPlan"]},"testPlan":{"type":"string","description":"Test Plan","ignoreCase":"key"},"testSuite":{"type":"string","description":"Test Suite","ignoreCase":"key"},"testConfiguration":{"type":"string","description":"Test Configuration","ignoreCase":"key"},"sourcefilters":{"type":"string","description":"Test Assembly","ignoreCase":"key"},"testFilterCriteria":{"type":"string","description":"Test Filter criteria","ignoreCase":"key"},"runSettingsFile":{"type":"string","description":"Run Settings File","ignoreCase":"key"},"overrideRunParams":{"type":"string","description":"Override Test Run Parameters","ignoreCase":"key"},"codeCoverageEnabled":{"type":"boolean","description":"Code Coverage Enabled","ignoreCase":"key"},"customSlicingEnabled":{"type":"boolean","description":"Distribute tests by number of machines","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test Run Title","ignoreCase":"key"},"platform":{"type":"string","description":"Platform","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"testConfigurations":{"type":"string","description":"Test Configurations","ignoreCase":"key"},"autMachineGroup":{"type":"string","description":"Application Under Test Machines","ignoreCase":"key"}},"additionalProperties":false,"required":["testMachineGroup","dropLocation"]}},"deprecationMessage":"RunVisualStudioTestsusingTestAgent is deprecated - Deprecated: This task and it’s companion task (Visual Studio Test Agent Deployment) are deprecated. Use the 'Visual Studio Test' task instead. The VSTest task can run unit as well as functional tests. Run tests on one or more agents using the multi-agent job setting. Use the 'Visual Studio Test Platform' task to run tests without needing Visual Studio on the agent. VSTest task also brings new capabilities such as automatically rerunning failed tests.","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Shell++\n\nExecute bash script","ignoreCase":"value","pattern":"^Shellpp@0$"},"inputs":{"description":"Shell++ inputs","properties":{"type":{"description":"Type","ignoreCase":"all","enum":["InlineScript","FilePath"]},"scriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"cwd":{"type":"string","description":"Working Directory","ignoreCase":"key"},"failOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"},"script":{"type":"string","description":"Script","ignoreCase":"key"}},"additionalProperties":false,"required":["type"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Manual intervention\n\nPause deployment and wait for manual intervention","ignoreCase":"value","pattern":"^ManualIntervention@8$"},"inputs":{"description":"Manual intervention inputs","properties":{"instructions":{"type":"string","description":"Instructions","ignoreCase":"key"},"emailRecipients":{"type":"string","description":"Notify users","ignoreCase":"key"},"onTimeout":{"description":"On timeout","ignoreCase":"all","enum":["reject","resume"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Install Apple provisioning profile\n\nInstall an Apple provisioning profile required to build on a macOS agent machine","ignoreCase":"value","pattern":"^InstallAppleProvisioningProfile@1$"},"inputs":{"description":"Install Apple provisioning profile inputs","properties":{"provisioningProfileLocation":{"description":"Provisioning profile location","ignoreCase":"all","enum":["secureFiles","sourceRepository"]},"provProfileSecureFile":{"type":"string","description":"Provisioning profile","ignoreCase":"key"},"provProfileSourceRepository":{"type":"string","description":"Provisioning profile","ignoreCase":"key"},"removeProfile":{"type":"boolean","description":"Remove profile after build","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Install Apple Provisioning Profile\n\nInstall an Apple provisioning profile required to build on a macOS agent","ignoreCase":"value","pattern":"^InstallAppleProvisioningProfile@0$"},"inputs":{"description":"Install Apple Provisioning Profile inputs","properties":{"provProfileSecureFile":{"type":"string","description":"Provisioning Profile","ignoreCase":"key"},"removeProfile":{"type":"boolean","description":"Remove Profile After Build","ignoreCase":"key"}},"additionalProperties":false,"required":["provProfileSecureFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"SonarQube for MSBuild - End Analysis\n\n[DEPRECATED] Finish the analysis and upload the results to SonarQube","ignoreCase":"value","pattern":"^SonarQubePostTest@1$"},"inputs":{"description":"SonarQube for MSBuild - End Analysis inputs","properties":{},"additionalProperties":false,"required":[]}},"deprecationMessage":"SonarQubePostTest is deprecated - [DEPRECATED] Finish the analysis and upload the results to SonarQube","doNotSuggest":true,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Rich Code Navigation Indexer\n\nIndexes repository and stores navigation information","ignoreCase":"value","pattern":"^RichCodeNavIndexer@0$"},"inputs":{"description":"Rich Code Navigation Indexer inputs","properties":{"languages":{"type":"string","description":"Languages to index","ignoreCase":"key"},"githubServiceConnection":{"type":"string","description":"GitHub service connection","ignoreCase":"key"},"environment":{"description":"VS Rich Code Navigation Environment","ignoreCase":"all","enum":["production","staging","development"]},"nugetFeed":{"type":"string","description":"NuGet feed source","ignoreCase":"key"},"nugetVersion":{"type":"string","description":"VS Rich Code Navigation package version","ignoreCase":"key"},"isPrivateFeed":{"type":"boolean","description":"Is Private NuGet Feed?","ignoreCase":"key"},"configFiles":{"type":"string","description":"Project Configuration Files","ignoreCase":"key"},"richNavLogOutputDirectory":{"type":"string","description":"Rich Navigation MsBuild log files output directory","ignoreCase":"key"},"sourceRootDir":{"type":"string","description":"Root directory for source files if different than default","ignoreCase":"key"},"tempDirectory":{"type":"string","description":"Rich Nav temporary output directory","ignoreCase":"key"},"uploadRichNavArtifacts":{"type":"boolean","description":"Should Rich Nav logs be published as an artifact?","ignoreCase":"key"},"disableLsifLogging":{"type":"boolean","description":"Disable information logging from LSIF generation?","ignoreCase":"key"},"maxParallelIndexingJobs":{"type":"integer","description":"Max number of parallel indexing jobs","ignoreCase":"key"},"typescriptVersion":{"type":"string","description":"TypeScript tooling version","ignoreCase":"key"},"csharpVersion":{"type":"string","description":"Csharp tooling version","ignoreCase":"key"},"advancedOptionsCpp":{"type":"string","description":"Advanced c++ options","ignoreCase":"key"},"defaultExpiry":{"type":"integer","description":"Default Expiry","ignoreCase":"key"},"prExpiry":{"type":"integer","description":"PR Expiry","ignoreCase":"key"},"branchRetention":{"type":"string","description":"Branch Retention","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Insert VS Payload\n\nCreates a PR for a Payload Insertion into VS","ignoreCase":"value","pattern":"^MicroBuildInsertVsPayload@3$"},"inputs":{"description":"MicroBuild Insert VS Payload inputs","properties":{"TargetBranch":{"type":"string","description":"Target Branch","ignoreCase":"key"},"InsertionTopicBranch":{"type":"string","description":"Topic Branch Name","ignoreCase":"key"},"TeamName":{"type":"string","description":"Team Name","ignoreCase":"key"},"TeamEmail":{"type":"string","description":"Team Email Address","ignoreCase":"key"},"ComponentJsonValues":{"type":"string","description":"Component.json Values","ignoreCase":"key"},"DefaultConfigValues":{"type":"string","description":"Default.config Values","ignoreCase":"key"},"PackagePropsValues":{"type":"string","description":"Packages.props Values","ignoreCase":"key"},"AssemblyVersionsValues":{"type":"string","description":"AssemblyVersions.tt Values","ignoreCase":"key"},"RevisionTextFiles":{"type":"string","description":"Revision.txt Files","ignoreCase":"key"},"CustomScriptExecutionCommand":{"type":"string","description":"Custom Script Execution Command","ignoreCase":"key"},"InsertionPayloadName":{"type":"string","description":"Payload Name","ignoreCase":"key"},"SkipCreatePR":{"type":"boolean","description":"Do Not Create","ignoreCase":"key"},"AllowTopicBranchUpdate":{"type":"boolean","description":"Allow Topic Branch Update","ignoreCase":"key"},"InsertionDescription":{"type":"string","description":"Description","ignoreCase":"key"},"InsertionReviewers":{"type":"string","description":"Reviewers","ignoreCase":"key"},"InsertionBuildPolicy":{"description":"Build Policy to Queue","ignoreCase":"all","enum":["Request Perf DDRITs"]},"InsertionAccessToken":{"type":"string","description":"Access Token to Use","ignoreCase":"key"},"InsertionWaitMinutes":{"type":"string","description":"Minutes to Wait for PR Completion","ignoreCase":"key"},"AutoCompletePR":{"type":"boolean","description":"Set AutoComplete","ignoreCase":"key"},"AutoCompleteMergeStrategy":{"description":"AutoComplete Merge Strategy","ignoreCase":"all","enum":["NoFastForward","Squash","Rebase","RebaseMerge"]},"AddCommitsToPR":{"type":"boolean","description":"Add Related Commits","ignoreCase":"key"},"CommitsFile":{"type":"string","description":"File Containing Commit Ids","ignoreCase":"key"},"CommitsUri":{"type":"string","description":"Uri to Commits Repo","ignoreCase":"key"},"AddCommitAuthorsToPR":{"type":"boolean","description":"Add Commit Authors to Reviewers","ignoreCase":"key"},"LinkWorkItemsToPR":{"type":"boolean","description":"Link Work Items","ignoreCase":"key"},"AccountUri":{"type":"string","description":"Target Account Uri","ignoreCase":"key"},"TeamProject":{"type":"string","description":"Target Team Project","ignoreCase":"key"},"Repository":{"type":"string","description":"Target Repository","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Insert VS Payload\n\nCreates a PR for a Payload Insertion into VS","ignoreCase":"value","pattern":"^MicroBuildInsertVsPayload@4$"},"inputs":{"description":"MicroBuild Insert VS Payload inputs","properties":{"TargetBranch":{"type":"string","description":"Target Branch","ignoreCase":"key"},"InsertionTopicBranch":{"type":"string","description":"Topic Branch Name","ignoreCase":"key"},"TeamName":{"type":"string","description":"Team Name","ignoreCase":"key"},"TeamEmail":{"type":"string","description":"Team Email Address","ignoreCase":"key"},"ComponentJsonValues":{"type":"string","description":"Component.json Values","ignoreCase":"key"},"DefaultConfigValues":{"type":"string","description":"Default.config Values","ignoreCase":"key"},"PackagePropsValues":{"type":"string","description":"Packages.props Values","ignoreCase":"key"},"AssemblyVersionsValues":{"type":"string","description":"AssemblyVersions.tt Values","ignoreCase":"key"},"RevisionTextFiles":{"type":"string","description":"Revision.txt Files","ignoreCase":"key"},"ComponentSWRFiles":{"type":"string","description":"Component.swr Files","ignoreCase":"key"},"CustomScriptExecutionCommand":{"type":"string","description":"Custom Script Execution Command","ignoreCase":"key"},"InsertionPayloadName":{"type":"string","description":"Payload Name","ignoreCase":"key"},"SkipCreatePR":{"type":"boolean","description":"Do Not Create","ignoreCase":"key"},"AllowTopicBranchUpdate":{"type":"boolean","description":"Allow Topic Branch Update","ignoreCase":"key"},"InsertionDescription":{"type":"string","description":"Description","ignoreCase":"key"},"InsertionReviewers":{"type":"string","description":"Reviewers","ignoreCase":"key"},"InsertionBuildPolicy":{"description":"Build Policy to Queue","ignoreCase":"all","enum":["Request Perf DDRITs"]},"InsertionAccessToken":{"type":"string","description":"Access Token to Use","ignoreCase":"key"},"InsertionWaitMinutes":{"type":"string","description":"Minutes to Wait for PR Completion","ignoreCase":"key"},"AutoCompletePR":{"type":"boolean","description":"Set AutoComplete","ignoreCase":"key"},"AutoCompleteMergeStrategy":{"description":"AutoComplete Merge Strategy","ignoreCase":"all","enum":["NoFastForward","Squash","Rebase","RebaseMerge"]},"AddCommitsToPR":{"type":"boolean","description":"Add Related Commits","ignoreCase":"key"},"CommitsFile":{"type":"string","description":"File Containing Commit Ids","ignoreCase":"key"},"CommitsUri":{"type":"string","description":"Uri to Commits Repo","ignoreCase":"key"},"AddCommitAuthorsToPR":{"type":"boolean","description":"Add Commit Authors to Reviewers","ignoreCase":"key"},"LinkWorkItemsToPR":{"type":"boolean","description":"Link Work Items","ignoreCase":"key"},"AccountUri":{"type":"string","description":"Target Account Uri","ignoreCase":"key"},"TeamProject":{"type":"string","description":"Target Team Project","ignoreCase":"key"},"Repository":{"type":"string","description":"Target Repository","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"PyPI publisher\n\nCreate and upload an sdist or wheel to a PyPI-compatible index using Twine","ignoreCase":"value","pattern":"^PyPIPublisher@0$"},"inputs":{"description":"PyPI publisher inputs","properties":{"pypiConnection":{"type":"string","description":"PyPI service connection","ignoreCase":"key","aliases":["serviceEndpoint"]},"packageDirectory":{"type":"string","description":"Python package directory","ignoreCase":"key","aliases":["wd"]},"alsoPublishWheel":{"type":"boolean","description":"Also publish a wheel","ignoreCase":"key","aliases":["wheel"]}},"additionalProperties":false,"required":["pypiConnection","packageDirectory"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Chef Knife\n\nRun scripts with Knife commands on your Chef workstation","ignoreCase":"value","pattern":"^ChefKnife@1$"},"inputs":{"description":"Chef Knife inputs","properties":{"ConnectedServiceName":{"type":"string","description":"Chef Subscription","ignoreCase":"key"},"ScriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":["ConnectedServiceName","ScriptPath"]}},"deprecationMessage":"ChefKnife is deprecated - Run scripts with Knife commands on your Chef workstation","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Go tool installer\n\nFind in cache or download a specific version of Go and add it to the PATH","ignoreCase":"value","pattern":"^GoTool@0$"},"inputs":{"description":"Go tool installer inputs","properties":{"version":{"type":"string","description":"Version","ignoreCase":"key"},"goPath":{"type":"string","description":"GOPATH","ignoreCase":"key"},"goBin":{"type":"string","description":"GOBIN","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure Web App Route Traffic\n\nRoutes traffic of a Web App to an App Slot by the specified percentage","ignoreCase":"value","pattern":"^azureWebAppRouteTraffic@0$"},"inputs":{"description":"Azure Web App Route Traffic inputs","properties":{"ConnectedServiceName":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"WebAppName":{"type":"string","description":"App Service name","ignoreCase":"key"},"ResourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"Slot":{"type":"string","description":"Experiment slot","ignoreCase":"key"},"percentTraffic":{"type":"string","description":"Percentage to Route","ignoreCase":"key"}},"additionalProperties":false,"required":["ConnectedServiceName","WebAppName","ResourceGroupName","Slot","percentTraffic"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Xcode Package iOS\n\nGenerate an .ipa file from Xcode build output using xcrun (Xcode 7 or below)","ignoreCase":"value","pattern":"^XcodePackageiOS@0$"},"inputs":{"description":"Xcode Package iOS inputs","properties":{"appName":{"type":"string","description":"Name of .app","ignoreCase":"key"},"ipaName":{"type":"string","description":"Name of .ipa","ignoreCase":"key"},"provisioningProfile":{"type":"string","description":"Provisioning Profile Name","ignoreCase":"key"},"sdk":{"type":"string","description":"SDK","ignoreCase":"key"},"appPath":{"type":"string","description":"Path to .app","ignoreCase":"key"},"ipaPath":{"type":"string","description":"Path to place .ipa","ignoreCase":"key"}},"additionalProperties":false,"required":["provisioningProfile"]}},"deprecationMessage":"XcodePackageiOS is deprecated - Generate an .ipa file from Xcode build output using xcrun (Xcode 7 or below)","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Go\n\nGet, build, or test a Go application, or run a custom Go command","ignoreCase":"value","pattern":"^Go@0$"},"inputs":{"description":"Go inputs","properties":{"command":{"description":"Command","ignoreCase":"all","enum":["get","build","test","custom"]},"customCommand":{"type":"string","description":"Custom command","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Tokenize with XPath/Regular expressions\n\nReplaces ____ and/or XPath for XML documents with User Defined variables or configuration json document","ignoreCase":"value","pattern":"^Tokenizer@2$"},"inputs":{"description":"Tokenize with XPath/Regular expressions inputs","properties":{"SourcePath":{"type":"string","description":"Source filename","ignoreCase":"key"},"DestinationPath":{"type":"string","description":"Destination filename","ignoreCase":"key"},"ConfigurationJsonFile":{"type":"string","description":"Configuration Json filename","ignoreCase":"key"},"ReplaceUndefinedValuesWithEmpty":{"type":"boolean","description":"Replace undefined values with empty","ignoreCase":"key"}},"additionalProperties":false,"required":["SourcePath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Publish Pipeline Metadata\n\nPublish Pipeline Metadata to Evidence store","ignoreCase":"value","pattern":"^PublishPipelineMetadata@0$"},"inputs":{"description":"Publish Pipeline Metadata inputs","properties":{},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Docker\n\nBuild, tag, push, or run Docker images, or run a Docker command","ignoreCase":"value","pattern":"^Docker@1$"},"inputs":{"description":"Docker inputs","properties":{"containerregistrytype":{"description":"Container registry type","ignoreCase":"all","enum":["Azure Container Registry","Container Registry"]},"addBaseImageData":{"type":"boolean","description":"Add base image metadata to image(s)","ignoreCase":"key"},"dockerRegistryEndpoint":{"type":"string","description":"Docker registry service connection","ignoreCase":"key"},"azureSubscriptionEndpoint":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"azureContainerRegistry":{"type":"string","description":"Azure container registry","ignoreCase":"key"},"command":{"description":"Command","ignoreCase":"all","enum":["Build an image","Tag image","Push an image","Run an image","login","logout"]},"dockerFile":{"type":"string","description":"Dockerfile","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"pushMultipleImages":{"type":"boolean","description":"Push multiple images","ignoreCase":"key"},"tagMultipleImages":{"type":"boolean","description":"Tag multiple images","ignoreCase":"key"},"imageName":{"type":"string","description":"Image name","ignoreCase":"key"},"imageNamesPath":{"type":"string","description":"Image names path","ignoreCase":"key"},"qualifyImageName":{"type":"boolean","description":"Qualify image name","ignoreCase":"key"},"qualifySourceImageName":{"type":"boolean","description":"Qualify source image name","ignoreCase":"key"},"includeSourceTags":{"type":"boolean","description":"Include source tags","ignoreCase":"key"},"includeLatestTag":{"type":"boolean","description":"Include latest tag","ignoreCase":"key"},"addDefaultLabels":{"type":"boolean","description":"Add default labels","ignoreCase":"key"},"useDefaultContext":{"type":"boolean","description":"Use default build context","ignoreCase":"key"},"buildContext":{"type":"string","description":"Build context","ignoreCase":"key"},"imageDigestFile":{"type":"string","description":"Image digest file","ignoreCase":"key"},"containerName":{"type":"string","description":"Container name","ignoreCase":"key"},"ports":{"type":"string","description":"Ports","ignoreCase":"key"},"volumes":{"type":"string","description":"Volumes","ignoreCase":"key"},"envVars":{"type":"string","description":"Environment variables","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key"},"entrypointOverride":{"type":"string","description":"Entry point override","ignoreCase":"key"},"containerCommand":{"type":"string","description":"Container command","ignoreCase":"key"},"runInBackground":{"type":"boolean","description":"Run in background","ignoreCase":"key"},"restartPolicy":{"description":"Restart policy","ignoreCase":"all","enum":["no","onFailure","always","unlessStopped"]},"maxRestartRetries":{"type":"string","description":"Maximum restart retries","ignoreCase":"key"},"dockerHostEndpoint":{"type":"string","description":"Docker host service connection","ignoreCase":"key"},"enforceDockerNamingConvention":{"type":"boolean","description":"Force image name to follow Docker naming convention","ignoreCase":"key"},"memoryLimit":{"type":"string","description":"Memory limit","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Docker\n\nBuild or push Docker images, login or logout, start or stop containers, or run a Docker command","ignoreCase":"value","pattern":"^Docker@2$"},"inputs":{"description":"Docker inputs","properties":{"containerRegistry":{"type":"string","description":"Container registry","ignoreCase":"key"},"repository":{"type":"string","description":"Container repository","ignoreCase":"key"},"command":{"description":"Command","ignoreCase":"all","enum":["buildAndPush","build","push","login","logout","start","stop"]},"Dockerfile":{"type":"string","description":"Dockerfile","ignoreCase":"key"},"buildContext":{"type":"string","description":"Build context","ignoreCase":"key"},"tags":{"type":"string","description":"Tags","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"addPipelineData":{"type":"boolean","description":"Add Pipeline metadata to image(s)","ignoreCase":"key"},"addBaseImageData":{"type":"boolean","description":"Add base image metadata to image(s)","ignoreCase":"key"},"container":{"type":"string","description":"Container","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Docker\n\nBuild, tag, push, or run Docker images, or run a Docker command","ignoreCase":"value","pattern":"^Docker@0$"},"inputs":{"description":"Docker inputs","properties":{"containerregistrytype":{"description":"Container Registry Type","ignoreCase":"all","enum":["Azure Container Registry","Container Registry"]},"dockerRegistryConnection":{"type":"string","description":"Docker Registry Service Connection","ignoreCase":"key","aliases":["dockerRegistryEndpoint"]},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["azureSubscriptionEndpoint"]},"azureContainerRegistry":{"type":"string","description":"Azure Container Registry","ignoreCase":"key"},"action":{"description":"Action","ignoreCase":"all","enum":["Build an image","Tag images","Push an image","Push images","Run an image","Run a Docker command"]},"dockerFile":{"type":"string","description":"Docker File","ignoreCase":"key"},"addBaseImageData":{"type":"boolean","description":"Add base image metadata to image(s)","ignoreCase":"key"},"buildArguments":{"type":"string","description":"Build Arguments","ignoreCase":"key"},"defaultContext":{"type":"boolean","description":"Use Default Build Context","ignoreCase":"key"},"context":{"type":"string","description":"Build Context","ignoreCase":"key"},"imageName":{"type":"string","description":"Image Name","ignoreCase":"key"},"imageNamesPath":{"type":"string","description":"Image Names Path","ignoreCase":"key"},"qualifyImageName":{"type":"boolean","description":"Qualify Image Name","ignoreCase":"key"},"additionalImageTags":{"type":"string","description":"Additional Image Tags","ignoreCase":"key"},"includeSourceTags":{"type":"boolean","description":"Include Source Tags","ignoreCase":"key"},"includeLatestTag":{"type":"boolean","description":"Include Latest Tag","ignoreCase":"key"},"imageDigestFile":{"type":"string","description":"Image Digest File","ignoreCase":"key"},"containerName":{"type":"string","description":"Container Name","ignoreCase":"key"},"ports":{"type":"string","description":"Ports","ignoreCase":"key"},"volumes":{"type":"string","description":"Volumes","ignoreCase":"key"},"envVars":{"type":"string","description":"Environment Variables","ignoreCase":"key"},"workDir":{"type":"string","description":"Working Directory","ignoreCase":"key"},"entrypoint":{"type":"string","description":"Entry Point Override","ignoreCase":"key"},"containerCommand":{"type":"string","description":"Command","ignoreCase":"key"},"detached":{"type":"boolean","description":"Run In Background","ignoreCase":"key"},"restartPolicy":{"description":"Restart Policy","ignoreCase":"all","enum":["no","onFailure","always","unlessStopped"]},"restartMaxRetries":{"type":"string","description":"Maximum Restart Retries","ignoreCase":"key"},"customCommand":{"type":"string","description":"Command","ignoreCase":"key"},"dockerHostEndpoint":{"type":"string","description":"Docker Host Service Connection","ignoreCase":"key"},"enforceDockerNamingConvention":{"type":"boolean","description":"Force image name to follow Docker naming convention","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["cwd"]},"memory":{"type":"string","description":"Memory limit","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Publish Artifact Services Drop -preview\n\nPublish to Artifact Services Drop - Internal Preview","ignoreCase":"value","pattern":"^artifactDropTask@0$"},"inputs":{"description":"Publish Artifact Services Drop -preview inputs","properties":{"dropServiceURI":{"type":"string","description":"Drop Service Endpoint","ignoreCase":"key"},"buildNumber":{"type":"string","description":"Drop Name","ignoreCase":"key"},"sourcePath":{"type":"string","description":"Upload Source Root Path","ignoreCase":"key"},"dropExePath":{"type":"string","description":"Override drop.exe Path","ignoreCase":"key"},"toLowerCase":{"type":"boolean","description":"Lowercase drop name","ignoreCase":"key"},"detailedLog":{"type":"boolean","description":"Verbose Logging","ignoreCase":"key"},"usePat":{"type":"boolean","description":"Use Personal Access Token","ignoreCase":"key"},"retentionDays":{"type":"string","description":"Retention (in days)","ignoreCase":"key"},"dropMetadataContainerName":{"type":"string","description":"Drop Metadata Container Name","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Jenkins queue job\n\nQueue a job on a Jenkins server","ignoreCase":"value","pattern":"^JenkinsQueueJob@2$"},"inputs":{"description":"Jenkins queue job inputs","properties":{"serverEndpoint":{"type":"string","description":"Jenkins service connection","ignoreCase":"key"},"jobName":{"type":"string","description":"Job name","ignoreCase":"key"},"isMultibranchJob":{"type":"boolean","description":"Job is of multibranch pipeline type","ignoreCase":"key"},"multibranchPipelineBranch":{"type":"string","description":"Multibranch pipeline branch","ignoreCase":"key"},"captureConsole":{"type":"boolean","description":"Capture console output and wait for completion","ignoreCase":"key"},"capturePipeline":{"type":"boolean","description":"Capture pipeline output and wait for pipeline completion","ignoreCase":"key"},"isParameterizedJob":{"type":"boolean","description":"Parameterized job","ignoreCase":"key","aliases":["parameterizedJob"]},"jobParameters":{"type":"string","description":"Job parameters","ignoreCase":"key"},"failOnUnstableResult":{"type":"boolean","description":"Fail on unstable result","ignoreCase":"key"},"retryCount":{"type":"string","description":"Number of retries for failed connection","ignoreCase":"key"},"delayBetweenRetries":{"type":"string","description":"Time between retries","ignoreCase":"key"}},"additionalProperties":false,"required":["serverEndpoint","jobName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Jenkins Queue Job\n\nQueue a job on a Jenkins server","ignoreCase":"value","pattern":"^JenkinsQueueJob@1$"},"inputs":{"description":"Jenkins Queue Job inputs","properties":{"serverEndpoint":{"type":"string","description":"Jenkins service endpoint","ignoreCase":"key"},"jobName":{"type":"string","description":"Job name","ignoreCase":"key"},"isMultibranchJob":{"type":"boolean","description":"Job is of Multibranch Pipeline type","ignoreCase":"key"},"multibranchPipelineBranch":{"type":"string","description":"Multibranch Pipeline Branch","ignoreCase":"key"},"captureConsole":{"type":"boolean","description":"Capture console output and wait for completion","ignoreCase":"key"},"capturePipeline":{"type":"boolean","description":"Capture pipeline output and wait for pipeline completion","ignoreCase":"key"},"parameterizedJob":{"type":"boolean","description":"Parameterized job","ignoreCase":"key"},"jobParameters":{"type":"string","description":"Job parameters","ignoreCase":"key"}},"additionalProperties":false,"required":["serverEndpoint","jobName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"FTP upload\n\nUpload files using FTP","ignoreCase":"value","pattern":"^FtpUpload@1$"},"inputs":{"description":"FTP upload inputs","properties":{"credentialsOption":{"description":"Authentication Method","ignoreCase":"all","enum":["serviceEndpoint","inputs"],"aliases":["credsType"]},"serverEndpoint":{"type":"string","description":"FTP Service Connection","ignoreCase":"key"},"serverUrl":{"type":"string","description":"Server URL","ignoreCase":"key"},"username":{"type":"string","description":"Username","ignoreCase":"key"},"password":{"type":"string","description":"Password","ignoreCase":"key"},"rootDirectory":{"type":"string","description":"Root folder","ignoreCase":"key","aliases":["rootFolder"]},"filePatterns":{"type":"string","description":"File patterns","ignoreCase":"key"},"remoteDirectory":{"type":"string","description":"Remote directory","ignoreCase":"key","aliases":["remotePath"]},"clean":{"type":"boolean","description":"Delete remote directory","ignoreCase":"key"},"cleanContents":{"type":"boolean","description":"Clear remote directory contents","ignoreCase":"key"},"overwrite":{"type":"boolean","description":"Overwrite","ignoreCase":"key"},"preservePaths":{"type":"boolean","description":"Preserve file paths","ignoreCase":"key"},"trustSSL":{"type":"boolean","description":"Trust server certificate","ignoreCase":"key"}},"additionalProperties":false,"required":["rootDirectory"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"FTP upload\n\nUpload files using FTP","ignoreCase":"value","pattern":"^FtpUpload@2$"},"inputs":{"description":"FTP upload inputs","properties":{"credentialsOption":{"description":"Authentication Method","ignoreCase":"all","enum":["serviceEndpoint","inputs"],"aliases":["credsType"]},"serverEndpoint":{"type":"string","description":"FTP Service Connection","ignoreCase":"key"},"serverUrl":{"type":"string","description":"Server URL","ignoreCase":"key"},"username":{"type":"string","description":"Username","ignoreCase":"key"},"password":{"type":"string","description":"Password","ignoreCase":"key"},"rootDirectory":{"type":"string","description":"Root folder","ignoreCase":"key","aliases":["rootFolder"]},"filePatterns":{"type":"string","description":"File patterns","ignoreCase":"key"},"remoteDirectory":{"type":"string","description":"Remote directory","ignoreCase":"key","aliases":["remotePath"]},"enableUtf8":{"type":"boolean","description":"Enable UTF8 support","ignoreCase":"key"},"clean":{"type":"boolean","description":"Delete remote directory","ignoreCase":"key"},"cleanContents":{"type":"boolean","description":"Clear remote directory contents","ignoreCase":"key"},"preservePaths":{"type":"boolean","description":"Preserve file paths","ignoreCase":"key"},"trustSSL":{"type":"boolean","description":"Trust server certificate","ignoreCase":"key"},"customCmds":{"type":"string","description":"FTP Commands","ignoreCase":"key"}},"additionalProperties":false,"required":["rootDirectory"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Windows machine file copy\n\nCopy files to remote Windows machines","ignoreCase":"value","pattern":"^WindowsMachineFileCopy@1$"},"inputs":{"description":"Windows machine file copy inputs","properties":{"SourcePath":{"type":"string","description":"Source","ignoreCase":"key"},"EnvironmentName":{"type":"string","description":"Machines","ignoreCase":"key"},"AdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"AdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"TargetPath":{"type":"string","description":"Destination Folder","ignoreCase":"key"},"CleanTargetBeforeCopy":{"type":"boolean","description":"Clean Target","ignoreCase":"key"},"CopyFilesInParallel":{"type":"boolean","description":"Copy Files in Parallel","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"},"ResourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"MachineNames":{"type":"string","description":"Filter Criteria","ignoreCase":"key"}},"additionalProperties":false,"required":["SourcePath","TargetPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Windows machine file copy\n\nCopy files to remote Windows machines","ignoreCase":"value","pattern":"^WindowsMachineFileCopy@2$"},"inputs":{"description":"Windows machine file copy inputs","properties":{"SourcePath":{"type":"string","description":"Source","ignoreCase":"key"},"MachineNames":{"type":"string","description":"Machines","ignoreCase":"key"},"AdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"AdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"TargetPath":{"type":"string","description":"Destination Folder","ignoreCase":"key"},"CleanTargetBeforeCopy":{"type":"boolean","description":"Clean Target","ignoreCase":"key"},"CopyFilesInParallel":{"type":"boolean","description":"Copy Files in Parallel","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":["SourcePath","TargetPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Send email\n\nSend an email to 1 or more addresses via the SMTP server you provide","ignoreCase":"value","pattern":"^SendEmail@1$"},"inputs":{"description":"Send email inputs","properties":{"To":{"type":"string","description":"To Addresses","ignoreCase":"key"},"CC":{"type":"string","description":"CC Addresses","ignoreCase":"key"},"BCC":{"type":"string","description":"BCC Addresses","ignoreCase":"key"},"From":{"type":"string","description":"From Address","ignoreCase":"key"},"Subject":{"type":"string","description":"Mail Subject","ignoreCase":"key"},"Body":{"type":"string","description":"Mail Body","ignoreCase":"key"},"BodyAsHtml":{"type":"boolean","description":"Is HTML Body?:","ignoreCase":"key"},"AddAttachment":{"type":"boolean","description":"Add Attachment?:","ignoreCase":"key"},"Attachment":{"type":"string","description":"Attachment (absolute path)","ignoreCase":"key"},"SmtpServer":{"type":"string","description":"SMTP Server","ignoreCase":"key"},"SmtpPort":{"type":"string","description":"SMTP Port","ignoreCase":"key"},"SmtpUsername":{"type":"string","description":"SMTP Username","ignoreCase":"key"},"SmtpPassword":{"type":"string","description":"SMTP Password","ignoreCase":"key"},"UseSSL":{"type":"boolean","description":"SMTP Use SSL?","ignoreCase":"key"}},"additionalProperties":false,"required":["To","From","Subject"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Android Build\n\n[Deprecated] Use Gradle","ignoreCase":"value","pattern":"^AndroidBuild@1$"},"inputs":{"description":"Android Build inputs","properties":{"gradleWrapper":{"type":"string","description":"Location of Gradle Wrapper","ignoreCase":"key"},"gradleProj":{"type":"string","description":"Project Directory","ignoreCase":"key"},"gradleArguments":{"type":"string","description":"Gradle Arguments","ignoreCase":"key"},"avdName":{"type":"string","description":"Name","ignoreCase":"key"},"createAvd":{"type":"boolean","description":"Create AVD","ignoreCase":"key"},"emulatorTarget":{"type":"string","description":"AVD Target SDK","ignoreCase":"key"},"emulatorDevice":{"type":"string","description":"AVD Device","ignoreCase":"key"},"avdAbi":{"type":"string","description":"AVD ABI","ignoreCase":"key"},"avdForce":{"type":"boolean","description":"Overwrite Existing AVD","ignoreCase":"key"},"avdOptionalArgs":{"type":"string","description":"Create AVD Optional Arguments","ignoreCase":"key"},"startEmulator":{"type":"boolean","description":"Start and Stop Android Emulator","ignoreCase":"key"},"emulatorTimeout":{"type":"string","description":"Timeout in Seconds","ignoreCase":"key"},"emulatorHeadless":{"type":"boolean","description":"Headless Display","ignoreCase":"key"},"emulatorOptionalArgs":{"type":"string","description":"Emulator Optional Arguments","ignoreCase":"key"},"deleteAvd":{"type":"boolean","description":"Delete AVD","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"deprecationMessage":"AndroidBuild is deprecated - [Deprecated] Use Gradle","doNotSuggest":true,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Python twine upload authenticate\n\nAuthenticate for uploading Python distributions using twine. Add '-r FeedName/EndpointName --config-file $(PYPIRC_PATH)' to your twine upload command. For feeds present in this organization, use the feed name as the repository (-r). Otherwise, use the endpoint name defined in the service connection.","ignoreCase":"value","pattern":"^TwineAuthenticate@1$"},"inputs":{"description":"Python twine upload authenticate inputs","properties":{"artifactFeed":{"type":"string","description":"My feed (select below)","ignoreCase":"key","aliases":["artifactFeed"]},"pythonUploadServiceConnection":{"type":"string","description":"Feed from external organizations","ignoreCase":"key","aliases":["pythonUploadServiceConnection"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Python twine upload authenticate\n\nAuthenticate for uploading Python distributions using twine. Add '-r FeedName/EndpointName --config-file $(PYPIRC_PATH)' to your twine upload command. For feeds present in this organization, use the feed name as the repository (-r). Otherwise, use the endpoint name defined in the service connection.","ignoreCase":"value","pattern":"^TwineAuthenticate@0$"},"inputs":{"description":"Python twine upload authenticate inputs","properties":{"artifactFeeds":{"type":"string","description":"My feeds (select below)","ignoreCase":"key","aliases":["feedList"]},"externalFeeds":{"type":"string","description":"Feeds from external organizations","ignoreCase":"key","aliases":["externalSources"]},"publishPackageMetadata":{"type":"boolean","description":"Publish pipeline metadata","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"IIS web app deploy\n\nDeploy a website or web application using Web Deploy","ignoreCase":"value","pattern":"^IISWebAppDeploymentOnMachineGroup@0$"},"inputs":{"description":"IIS web app deploy inputs","properties":{"WebSiteName":{"type":"string","description":"Website Name","ignoreCase":"key"},"VirtualApplication":{"type":"string","description":"Virtual Application","ignoreCase":"key"},"Package":{"type":"string","description":"Package or Folder","ignoreCase":"key"},"SetParametersFile":{"type":"string","description":"SetParameters File","ignoreCase":"key"},"RemoveAdditionalFilesFlag":{"type":"boolean","description":"Remove Additional Files at Destination","ignoreCase":"key"},"ExcludeFilesFromAppDataFlag":{"type":"boolean","description":"Exclude Files from the App_Data Folder","ignoreCase":"key"},"TakeAppOfflineFlag":{"type":"boolean","description":"Take App Offline","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"},"XmlTransformation":{"type":"boolean","description":"XML transformation","ignoreCase":"key"},"XmlVariableSubstitution":{"type":"boolean","description":"XML variable substitution","ignoreCase":"key"},"JSONFiles":{"type":"string","description":"JSON variable substitution","ignoreCase":"key"}},"additionalProperties":false,"required":["WebSiteName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Python script\n\nRun a Python file or inline script","ignoreCase":"value","pattern":"^PythonScript@0$"},"inputs":{"description":"Python script inputs","properties":{"scriptSource":{"description":"Script source","ignoreCase":"all","enum":["filePath","inline"]},"scriptPath":{"type":"string","description":"Script path","ignoreCase":"key"},"script":{"type":"string","description":"Script","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"pythonInterpreter":{"type":"string","description":"Python interpreter","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key"},"failOnStderr":{"type":"boolean","description":"Fail on standard error","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Helm tool installer\n\nInstall Helm on an agent machine","ignoreCase":"value","pattern":"^HelmInstaller@1$"},"inputs":{"description":"Helm tool installer inputs","properties":{"helmVersionToInstall":{"type":"string","description":"Helm Version Spec","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Helm tool installer\n\nInstall Helm and Kubernetes on an agent machine","ignoreCase":"value","pattern":"^HelmInstaller@0$"},"inputs":{"description":"Helm tool installer inputs","properties":{"helmVersion":{"type":"string","description":"Helm Version Spec","ignoreCase":"key"},"checkLatestHelmVersion":{"type":"boolean","description":"Check for latest version of Helm","ignoreCase":"key"},"installKubectl":{"type":"boolean","description":"Install Kubectl","ignoreCase":"key","aliases":["installKubeCtl"]},"kubectlVersion":{"type":"string","description":"Kubectl Version Spec","ignoreCase":"key"},"checkLatestKubectl":{"type":"boolean","description":"Check for latest version of kubectl","ignoreCase":"key","aliases":["checkLatestKubeCtl"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Xamarin License\n\n[Deprecated] Upgrade to free version of Xamarin: https://store.xamarin.com","ignoreCase":"value","pattern":"^XamarinLicense@1$"},"inputs":{"description":"Xamarin License inputs","properties":{"action":{"description":"Action","ignoreCase":"all","enum":["Activate","Deactivate"]},"email":{"type":"string","description":"Email","ignoreCase":"key"},"password":{"type":"string","description":"Password","ignoreCase":"key"},"product":{"description":"Xamarin Product","ignoreCase":"all","enum":["MA","MT","MM"]},"timeout":{"type":"string","description":"Timeout in Seconds","ignoreCase":"key"}},"additionalProperties":false,"required":["email","password"]}},"deprecationMessage":"XamarinLicense is deprecated - [Deprecated] Upgrade to free version of Xamarin: https://store.xamarin.com","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"NuGet authenticate\n\nConfigure NuGet tools to authenticate with Azure Artifacts and other NuGet repositories. Requires NuGet >= 4.8.5385, dotnet >= 2.1.400, or MSBuild >= 15.8.166.59604","ignoreCase":"value","pattern":"^NuGetAuthenticate@0$"},"inputs":{"description":"NuGet authenticate inputs","properties":{"nuGetServiceConnections":{"type":"string","description":"Service connection credentials for feeds outside this organization","ignoreCase":"key"},"forceReinstallCredentialProvider":{"type":"boolean","description":"Reinstall the credential provider even if already installed","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Component Governance Detection\n\nInclude with your build to enable automatic Component Governance detection.","ignoreCase":"value","pattern":"^ComponentGovernanceComponentDetection@0$"},"inputs":{"description":"Component Governance Detection inputs","properties":{"scanType":{"description":"Scan mode","ignoreCase":"all","enum":["Register","LogOnly"]},"governanceProduct":{"type":"string","description":"Product","ignoreCase":"key"},"autoInjected":{"type":"boolean","description":"AutoInjected","ignoreCase":"key"},"whatif":{"type":"boolean","description":"[OBSOLETE] Whatif Mode (uncheck and use Scan Mode instead)","ignoreCase":"key"},"useDefaultDetectors":{"type":"boolean","description":"Use the default dependency detectors","ignoreCase":"key"},"detectorsToRun":{"description":"Dependency detectors override","ignoreCase":"all","enum":["NuGet","Npm","Maven"]},"verbosity":{"description":"Verbosity","ignoreCase":"all","enum":["Register","Normal","Verbose"]},"sourceScanPath":{"type":"string","description":"Working folder","ignoreCase":"key"},"detectorsFilter":{"type":"string","description":"Component detectors filter","ignoreCase":"key"},"dockerImagesToScan":{"type":"string","description":"Docker images to scan","ignoreCase":"key"},"alertWarningLevel":{"description":"Minimum alert severity to warn","ignoreCase":"all","enum":["Never","Critical","High","Medium","Low"]},"failOnAlert":{"type":"boolean","description":"Fail build on alerts above threshold","ignoreCase":"key"},"ignoreDirectories":{"type":"string","description":"Folder exclusion list","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Download GitHub Nuget Packages\n\nRestore your nuget packages using dotnet CLI","ignoreCase":"value","pattern":"^DownloadGitHubNugetPackage@1$"},"inputs":{"description":"Download GitHub Nuget Packages inputs","properties":{"packageName":{"type":"string","description":"Package Name","ignoreCase":"key"},"version":{"type":"string","description":"Package Version","ignoreCase":"key"},"externalFeedCredentials":{"type":"string","description":"Credentials for feed from GitHub","ignoreCase":"key","aliases":["externalEndpoints"]},"restoreDirectory":{"type":"string","description":"Destination directory","ignoreCase":"key","aliases":["packagesDirectory"]}},"additionalProperties":false,"required":["packageName","version"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Maven Authenticate\n\nProvides credentials for Azure Artifacts feeds and external maven repositories","ignoreCase":"value","pattern":"^MavenAuthenticate@0$"},"inputs":{"description":"Maven Authenticate inputs","properties":{"artifactsFeeds":{"type":"string","description":"Feeds","ignoreCase":"key"},"mavenServiceConnections":{"type":"string","description":"Credentials for repositories outside this organization/collection","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Review App\n\nUse this task under deploy phase provider to create a resource dynamically","ignoreCase":"value","pattern":"^ReviewApp@0$"},"inputs":{"description":"Review App inputs","properties":{"resourceName":{"type":"string","description":"Resource name","ignoreCase":"key"},"baseEnvironmentName":{"type":"string","description":"Environment name","ignoreCase":"key"},"reviewResourceName":{"type":"string","description":"Review Resource Name","ignoreCase":"key"}},"additionalProperties":false,"required":["resourceName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Java tool installer\n\nAcquire a specific version of Java from a user-supplied Azure blob or the tool cache and sets JAVA_HOME","ignoreCase":"value","pattern":"^JavaToolInstaller@0$"},"inputs":{"description":"Java tool installer inputs","properties":{"versionSpec":{"type":"string","description":"JDK version","ignoreCase":"key"},"jdkArchitectureOption":{"description":"JDK architecture","ignoreCase":"all","enum":["x64","x86"]},"jdkSourceOption":{"description":"JDK source","ignoreCase":"all","enum":["AzureStorage","LocalDirectory","PreInstalled"]},"jdkFile":{"type":"string","description":"JDK file","ignoreCase":"key"},"azureResourceManagerEndpoint":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"azureStorageAccountName":{"type":"string","description":"Storage account name","ignoreCase":"key"},"azureContainerName":{"type":"string","description":"Container name","ignoreCase":"key"},"azureCommonVirtualFile":{"type":"string","description":"Common virtual path","ignoreCase":"key"},"jdkDestinationDirectory":{"type":"string","description":"Destination directory","ignoreCase":"key"},"cleanDestinationDirectory":{"type":"boolean","description":"Clean destination directory","ignoreCase":"key"},"createExtractDirectory":{"type":"boolean","description":"Create directory for extracting","ignoreCase":"key"}},"additionalProperties":false,"required":["jdkArchitectureOption","jdkSourceOption"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Chef\n\nDeploy to Chef environments by editing environment attributes","ignoreCase":"value","pattern":"^Chef@1$"},"inputs":{"description":"Chef inputs","properties":{"connectedServiceName":{"type":"string","description":"Chef Service Connection","ignoreCase":"key"},"Environment":{"type":"string","description":"Environment","ignoreCase":"key"},"Attributes":{"type":"string","description":"Environment Attributes","ignoreCase":"key"},"chefWaitTime":{"type":"string","description":"Wait Time","ignoreCase":"key"}},"additionalProperties":false,"required":["connectedServiceName","Environment","Attributes"]}},"deprecationMessage":"Chef is deprecated - Deploy to Chef environments by editing environment attributes","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure Functions\n\nUpdate a function app with .NET, Python, JavaScript, PowerShell, Java based web applications","ignoreCase":"value","pattern":"^AzureFunctionApp@1$"},"inputs":{"description":"Azure Functions inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"appType":{"description":"App type","ignoreCase":"all","enum":["functionApp","functionAppLinux"]},"appName":{"type":"string","description":"App name","ignoreCase":"key"},"deployToSlotOrASE":{"type":"boolean","description":"Deploy to Slot or App Service Environment","ignoreCase":"key"},"resourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"slotName":{"type":"string","description":"Slot","ignoreCase":"key"},"package":{"type":"string","description":"Package or folder","ignoreCase":"key"},"runtimeStack":{"description":"Runtime stack","ignoreCase":"all","enum":["DOTNET|2.2","DOTNET|3.1","JAVA|8","JAVA|11","NODE|8","NODE|10","NODE|12","NODE|14","PYTHON|3.6","PYTHON|3.7","PYTHON|3.8"]},"startUpCommand":{"type":"string","description":"Startup command ","ignoreCase":"key"},"customWebConfig":{"type":"string","description":"Generate web.config parameters for Python, Node.js, Go and Java apps","ignoreCase":"key"},"appSettings":{"type":"string","description":"App settings","ignoreCase":"key"},"configurationStrings":{"type":"string","description":"Configuration settings","ignoreCase":"key"},"deploymentMethod":{"description":"Deployment method","ignoreCase":"all","enum":["auto","zipDeploy","runFromPackage"]}},"additionalProperties":false,"required":["azureSubscription","appType","appName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"npm authenticate (for task runners)\n\nDon't use this task if you're also using the npm task. Provides npm credentials to an .npmrc file in your repository for the scope of the build. This enables npm task runners like gulp and Grunt to authenticate with private registries.","ignoreCase":"value","pattern":"^npmAuthenticate@0$"},"inputs":{"description":"npm authenticate (for task runners) inputs","properties":{"workingFile":{"type":"string","description":".npmrc file to authenticate","ignoreCase":"key"},"customEndpoint":{"type":"string","description":"Credentials for registries outside this organization/collection","ignoreCase":"key"}},"additionalProperties":false,"required":["workingFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MSBuild\n\nBuild with MSBuild","ignoreCase":"value","pattern":"^MSBuild@1$"},"inputs":{"description":"MSBuild inputs","properties":{"solution":{"type":"string","description":"Project","ignoreCase":"key"},"msbuildLocationMethod":{"description":"MSBuild","ignoreCase":"all","enum":["version","location"]},"msbuildVersion":{"description":"MSBuild Version","ignoreCase":"all","enum":["latest","17.0","16.0","15.0","14.0","12.0","4.0"]},"msbuildArchitecture":{"description":"MSBuild Architecture","ignoreCase":"all","enum":["x86","x64"]},"msbuildLocation":{"type":"string","description":"Path to MSBuild","ignoreCase":"key"},"platform":{"type":"string","description":"Platform","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"msbuildArguments":{"type":"string","description":"MSBuild Arguments","ignoreCase":"key"},"clean":{"type":"boolean","description":"Clean","ignoreCase":"key"},"maximumCpuCount":{"type":"boolean","description":"Build in Parallel","ignoreCase":"key"},"restoreNugetPackages":{"type":"boolean","description":"Restore NuGet Packages","ignoreCase":"key"},"logProjectEvents":{"type":"boolean","description":"Record Project Details","ignoreCase":"key"},"createLogFile":{"type":"boolean","description":"Create Log File","ignoreCase":"key"},"logFileVerbosity":{"description":"Log File Verbosity","ignoreCase":"all","enum":["quiet","minimal","normal","detailed","diagnostic"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Coverage Gate\n\nAdds a coverage trend summary section to the build report.","ignoreCase":"value","pattern":"^CoverageGate@1$"},"inputs":{"description":"Coverage Gate inputs","properties":{"minDelta":{"type":"string","description":"Delta","ignoreCase":"key"},"operator":{"description":"Operator","ignoreCase":"all","enum":["le","lt"]},"username":{"type":"string","description":"Username","ignoreCase":"key"},"password":{"type":"string","description":"Password","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Build machine image\n\nBuild a machine image using Packer, which may be used for Azure Virtual machine scale set deployment","ignoreCase":"value","pattern":"^PackerBuild@1$"},"inputs":{"description":"Build machine image inputs","properties":{"templateType":{"description":"Packer template","ignoreCase":"all","enum":["builtin","custom"]},"customTemplateLocation":{"type":"string","description":"Packer template location","ignoreCase":"key"},"customTemplateParameters":{"type":"string","description":"Template parameters","ignoreCase":"key"},"ConnectedServiceName":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"isManagedImage":{"type":"boolean","description":"Managed VM disk image","ignoreCase":"key"},"managedImageName":{"type":"string","description":"Managed VM Disk Image Name ","ignoreCase":"key"},"location":{"type":"string","description":"Storage location","ignoreCase":"key"},"storageAccountName":{"type":"string","description":"Storage account","ignoreCase":"key"},"azureResourceGroup":{"type":"string","description":"Resource group","ignoreCase":"key"},"baseImageSource":{"description":"Base image source","ignoreCase":"all","enum":["default","customVhd"]},"baseImage":{"description":"Base image","ignoreCase":"all","enum":["MicrosoftWindowsServer:WindowsServer:2012-R2-Datacenter:windows","MicrosoftWindowsServer:WindowsServer:2016-Datacenter:windows","MicrosoftWindowsServer:WindowsServer:2012-Datacenter:windows","MicrosoftWindowsServer:WindowsServer:2008-R2-SP1:windows","Canonical:UbuntuServer:14.04.4-LTS:linux","Canonical:UbuntuServer:16.04-LTS:linux","Canonical:UbuntuServer:18.04-LTS:linux","RedHat:RHEL:7.2:linux","RedHat:RHEL:6.8:linux","OpenLogic:CentOS:7.2:linux","OpenLogic:CentOS:6.8:linux","credativ:Debian:8:linux","credativ:Debian:7:linux","SUSE:openSUSE-Leap:42.2:linux","SUSE:SLES:12-SP2:linux","SUSE:SLES:11-SP4:linux"]},"customImageUrl":{"type":"string","description":"Base image URL","ignoreCase":"key"},"customImageOSType":{"description":"Base image OS","ignoreCase":"all","enum":["windows","linux"]},"packagePath":{"type":"string","description":"Deployment Package","ignoreCase":"key"},"deployScriptPath":{"type":"string","description":"Deployment script","ignoreCase":"key"},"deployScriptArguments":{"type":"string","description":"Deployment script arguments","ignoreCase":"key"},"additionalBuilderParameters":{"type":"string","description":"Additional Builder parameters","ignoreCase":"key"},"skipTempFileCleanupDuringVMDeprovision":{"type":"boolean","description":"Skip temporary file cleanup during deprovision","ignoreCase":"key"},"packerVersion":{"type":"string","description":"Packer Version","ignoreCase":"key"},"imageUri":{"type":"string","description":"Image URL or Name","ignoreCase":"key"},"imageId":{"type":"string","description":"Azure Resource Id","ignoreCase":"key"}},"additionalProperties":false,"required":["ConnectedServiceName","location","storageAccountName","azureResourceGroup","packagePath","deployScriptPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Build machine image\n\nBuild a machine image using Packer, which may be used for Azure Virtual machine scale set deployment","ignoreCase":"value","pattern":"^PackerBuild@0$"},"inputs":{"description":"Build machine image inputs","properties":{"templateType":{"description":"Packer template","ignoreCase":"all","enum":["builtin","custom"]},"customTemplateLocation":{"type":"string","description":"Packer template location","ignoreCase":"key"},"customTemplateParameters":{"type":"string","description":"Template parameters","ignoreCase":"key"},"ConnectedServiceName":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"location":{"type":"string","description":"Storage location","ignoreCase":"key"},"storageAccountName":{"type":"string","description":"Storage account","ignoreCase":"key"},"azureResourceGroup":{"type":"string","description":"Resource group","ignoreCase":"key"},"baseImageSource":{"description":"Base image source","ignoreCase":"all","enum":["default","customVhd"]},"baseImage":{"description":"Base image","ignoreCase":"all","enum":["MicrosoftWindowsServer:WindowsServer:2012-R2-Datacenter:windows","MicrosoftWindowsServer:WindowsServer:2016-Datacenter:windows","MicrosoftWindowsServer:WindowsServer:2012-Datacenter:windows","MicrosoftWindowsServer:WindowsServer:2008-R2-SP1:windows","Canonical:UbuntuServer:14.04.4-LTS:linux","Canonical:UbuntuServer:16.04-LTS:linux","RedHat:RHEL:7.2:linux","RedHat:RHEL:6.8:linux","OpenLogic:CentOS:7.2:linux","OpenLogic:CentOS:6.8:linux","credativ:Debian:8:linux","credativ:Debian:7:linux","SUSE:openSUSE-Leap:42.2:linux","SUSE:SLES:12-SP2:linux","SUSE:SLES:11-SP4:linux"]},"customImageUrl":{"type":"string","description":"Base image URL","ignoreCase":"key"},"customImageOSType":{"description":"Base image OS","ignoreCase":"all","enum":["windows","linux"]},"packagePath":{"type":"string","description":"Deployment Package","ignoreCase":"key"},"deployScriptPath":{"type":"string","description":"Deployment script","ignoreCase":"key"},"deployScriptArguments":{"type":"string","description":"Deployment script arguments","ignoreCase":"key"},"additionalBuilderParameters":{"type":"string","description":"Additional Builder parameters","ignoreCase":"key"},"skipTempFileCleanupDuringVMDeprovision":{"type":"boolean","description":"Skip temporary file cleanup during deprovision","ignoreCase":"key"},"imageUri":{"type":"string","description":"Image URL","ignoreCase":"key"}},"additionalProperties":false,"required":["ConnectedServiceName","location","storageAccountName","azureResourceGroup","packagePath","deployScriptPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Signing Plugin\n\nInstalls and configures the MicroBuild signing plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildSigningPlugin@4$"},"inputs":{"description":"MicroBuild Signing Plugin inputs","properties":{"signType":{"description":"Signing Type","ignoreCase":"all","enum":["test","real"]},"zipSources":{"type":"boolean","description":"Zip Sources When Real Signing","ignoreCase":"key"},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"skipAssetTest":{"type":"boolean","description":"Skip Asset Test When Real Signing","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Signing Plugin\n\nInstalls and configures the MicroBuild signing plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildSigningPlugin@1$"},"inputs":{"description":"MicroBuild Signing Plugin inputs","properties":{"signType":{"description":"Signing Type","ignoreCase":"all","enum":["test","real"]},"zipSources":{"type":"boolean","description":"Zip Sources When Real Signing","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"},"legacySigning":{"type":"boolean","description":"Use Legacy Signing When Real Signing","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Signing Plugin\n\n[Test-Xamarin-0.999.10 (all-lock)] Installs and configures the MicroBuild signing plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildSigningPlugin@0$"},"inputs":{"description":"MicroBuild Signing Plugin inputs","properties":{"signType":{"description":"Signing Type","ignoreCase":"all","enum":["test","real"]},"zipSources":{"type":"boolean","description":"Zip Sources When Real Signing","ignoreCase":"key"},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"skipAssetTest":{"type":"boolean","description":"Skip Asset Test When Real Signing","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Signing Plugin\n\nInstalls and configures the MicroBuild signing plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildSigningPlugin@3$"},"inputs":{"description":"MicroBuild Signing Plugin inputs","properties":{"signType":{"description":"Signing Type","ignoreCase":"all","enum":["test","real"]},"zipSources":{"type":"boolean","description":"Zip Sources When Real Signing","ignoreCase":"key"},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"skipAssetTest":{"type":"boolean","description":"Skip Asset Test When Real Signing","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Signing Plugin\n\nInstalls and configures the MicroBuild signing plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildSigningPlugin@2$"},"inputs":{"description":"MicroBuild Signing Plugin inputs","properties":{"signType":{"description":"Signing Type","ignoreCase":"all","enum":["test","real"]},"zipSources":{"type":"boolean","description":"Zip Sources When Real Signing","ignoreCase":"key"},"skipAssetTest":{"type":"boolean","description":"Skip Asset Test When Real Signing","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"NuGet packager\n\nDeprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","ignoreCase":"value","pattern":"^NuGetPackager@0$"},"inputs":{"description":"NuGet packager inputs","properties":{"searchPattern":{"type":"string","description":"Path to csproj or nuspec file(s) to pack","ignoreCase":"key"},"outputdir":{"type":"string","description":"Package Folder","ignoreCase":"key"},"includeReferencedProjects":{"type":"boolean","description":"Include referenced projects","ignoreCase":"key"},"versionByBuild":{"description":"Automatic package versioning","ignoreCase":"all","enum":["false","byPrereleaseNumber","byEnvVar","true"]},"versionEnvVar":{"type":"string","description":"Environment variable","ignoreCase":"key"},"requestedMajorVersion":{"type":"string","description":"Major","ignoreCase":"key"},"requestedMinorVersion":{"type":"string","description":"Minor","ignoreCase":"key"},"requestedPatchVersion":{"type":"string","description":"Patch","ignoreCase":"key"},"configurationToPack":{"type":"string","description":"Configuration to Package","ignoreCase":"key"},"buildProperties":{"type":"string","description":"Additional build properties","ignoreCase":"key"},"nuGetAdditionalArgs":{"type":"string","description":"NuGet Arguments","ignoreCase":"key"},"nuGetPath":{"type":"string","description":"Path to NuGet.exe","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"deprecationMessage":"NuGetPackager is deprecated - Deprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","doNotSuggest":true,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Update Service Fabric App Versions\n\nAutomatically updates the versions of a packaged Service Fabric application.","ignoreCase":"value","pattern":"^ServiceFabricUpdateAppVersions@1$"},"inputs":{"description":"Update Service Fabric App Versions inputs","properties":{"applicationPackagePath":{"type":"string","description":"Application Package","ignoreCase":"key"},"versionSuffix":{"type":"string","description":"Version Value","ignoreCase":"key"},"versionBehavior":{"description":"Version Behavior","ignoreCase":"all","enum":["Append","Replace"]},"updateOnlyChanged":{"type":"boolean","description":"Update only if changed","ignoreCase":"key"},"pkgArtifactName":{"type":"string","description":"Package Artifact Name","ignoreCase":"key"},"logAllChanges":{"type":"boolean","description":"Log all changes","ignoreCase":"key"},"compareType":{"description":"Compare against","ignoreCase":"all","enum":["LastSuccessful","Specific"]},"buildNumber":{"type":"string","description":"Build Number","ignoreCase":"key"}},"additionalProperties":false,"required":["applicationPackagePath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Update Service Fabric manifests\n\nAutomatically update portions of application and service manifests in a packaged Azure Service Fabric application","ignoreCase":"value","pattern":"^ServiceFabricUpdateManifests@2$"},"inputs":{"description":"Update Service Fabric manifests inputs","properties":{"updateType":{"description":"Update Type","ignoreCase":"all","enum":["Manifest versions","Docker image settings"]},"applicationPackagePath":{"type":"string","description":"Application Package","ignoreCase":"key"},"versionSuffix":{"type":"string","description":"Version Value","ignoreCase":"key"},"versionBehavior":{"description":"Version Behavior","ignoreCase":"all","enum":["Append","Replace"]},"updateOnlyChanged":{"type":"boolean","description":"Update only if changed","ignoreCase":"key"},"pkgArtifactName":{"type":"string","description":"Package Artifact Name","ignoreCase":"key"},"logAllChanges":{"type":"boolean","description":"Log all changes","ignoreCase":"key"},"compareType":{"description":"Compare against","ignoreCase":"all","enum":["LastSuccessful","Specific"]},"buildNumber":{"type":"string","description":"Build Number","ignoreCase":"key"},"overwriteExistingPkgArtifact":{"type":"boolean","description":"Overwrite Existing Package Artifact","ignoreCase":"key"},"imageNamesPath":{"type":"string","description":"Image Names Path","ignoreCase":"key"},"imageDigestsPath":{"type":"string","description":"Image Digests Path","ignoreCase":"key"}},"additionalProperties":false,"required":["applicationPackagePath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Duffle tool installer\n\nInstall a specified version of Duffle for installing and managing CNAB bundles","ignoreCase":"value","pattern":"^DuffleInstaller@0$"},"inputs":{"description":"Duffle tool installer inputs","properties":{"version":{"type":"string","description":"Version","ignoreCase":"key"},"checkLatestVersion":{"type":"boolean","description":"Check for latest version","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Query Azure Monitor alerts\n\nObserve the configured Azure Monitor rules for active alerts","ignoreCase":"value","pattern":"^AzureMonitor@1$"},"inputs":{"description":"Query Azure Monitor alerts inputs","properties":{"connectedServiceNameARM":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"ResourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"filterType":{"description":"Filter type","ignoreCase":"all","enum":["resource","alertrule","none"]},"resource":{"type":"string","description":"Resource","ignoreCase":"key"},"alertRule":{"type":"string","description":"Alert rule","ignoreCase":"key"},"severity":{"description":"Severity","ignoreCase":"all","enum":["Sev0","Sev1","Sev2","Sev3","Sev4"]},"timeRange":{"description":"Time range","ignoreCase":"all","enum":["1h","1d","7d","30d"]},"alertState":{"description":"Alert state","ignoreCase":"all","enum":["New","Acknowledged","Closed"]},"monitorCondition":{"description":"Monitor condition","ignoreCase":"all","enum":["Fired ","Resolved"]}},"additionalProperties":false,"required":["connectedServiceNameARM","ResourceGroupName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Query Classic Azure Monitor alerts\n\nObserve the configured classic Azure Monitor rules for active alerts","ignoreCase":"value","pattern":"^AzureMonitor@0$"},"inputs":{"description":"Query Classic Azure Monitor alerts inputs","properties":{"connectedServiceNameARM":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"ResourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"ResourceType":{"description":"Resource type","ignoreCase":"all","enum":["Microsoft.Insights/components","Microsoft.Web/sites","Microsoft.Storage/storageAccounts","Microsoft.Compute/virtualMachines"]},"resourceName":{"type":"string","description":"Resource name","ignoreCase":"key"},"alertRules":{"type":"string","description":"Alert rules","ignoreCase":"key"}},"additionalProperties":false,"required":["connectedServiceNameARM","ResourceGroupName","resourceName","alertRules"]}},"deprecationMessage":"AzureMonitor is deprecated - Observe the configured classic Azure Monitor rules for active alerts","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Generate Test Artifacts\n\nTask to generate runsettings and ADO Drop Urls as artifacts.","ignoreCase":"value","pattern":"^MicroBuildGenerateTestArtifacts@1$"},"inputs":{"description":"MicroBuild Generate Test Artifacts inputs","properties":{"BootstrapperInfoPath":{"type":"string","description":"Bootstrapper Info Path","ignoreCase":"key"},"BuildDropNamePrefix":{"type":"string","description":"Build Drop Name Prefix","ignoreCase":"key"},"TestDropNamePrefix":{"type":"string","description":"Test Drop Name Prefix","ignoreCase":"key"},"RunSettingsOutputFolder":{"type":"string","description":"Runsettings Output Folder","ignoreCase":"key"},"DropUrlsOutputFile":{"type":"string","description":"Drop Urls Output File","ignoreCase":"key"},"DropCoreVersion":{"type":"string","description":"Drop Core Version","ignoreCase":"key"},"DropCoreFeedSource":{"type":"string","description":"Drop Core Feed","ignoreCase":"key"},"NugetOrgPublicFeedSource":{"type":"string","description":"NuGet.org feed location","ignoreCase":"key"},"DropsPat":{"type":"string","description":"PAT for Drop Server","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure Network Load Balancer\n\nConnect or disconnect an Azure virtual machine's network interface to a Load Balancer's back end address pool","ignoreCase":"value","pattern":"^AzureNLBManagement@1$"},"inputs":{"description":"Azure Network Load Balancer inputs","properties":{"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"ResourceGroupName":{"type":"string","description":"Resource Group","ignoreCase":"key"},"LoadBalancer":{"type":"string","description":"Load Balancer Name","ignoreCase":"key"},"Action":{"description":"Action","ignoreCase":"all","enum":["Disconnect","Connect"]}},"additionalProperties":false,"required":["azureSubscription","ResourceGroupName","LoadBalancer","Action"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Cloud-based Apache JMeter load test\n\nRun an Apache JMeter load test in the cloud","ignoreCase":"value","pattern":"^ApacheJMeterLoadTest@1$"},"inputs":{"description":"Cloud-based Apache JMeter load test inputs","properties":{"connectedServiceName":{"type":"string","description":"Azure Pipelines Connection","ignoreCase":"key"},"TestDrop":{"type":"string","description":"Apache JMeter test files folder","ignoreCase":"key"},"LoadTest":{"type":"string","description":"Apache JMeter file","ignoreCase":"key"},"agentCount":{"description":"Agent Count","ignoreCase":"all","enum":["1","2","3","4","5"]},"runDuration":{"description":"Run Duration (sec)","ignoreCase":"all","enum":["60","120","180","240","300"]},"geoLocation":{"description":"Load Location","ignoreCase":"all","enum":["Default","Australia East","Australia Southeast","Brazil South","Central India","Central US","East Asia","East US 2","East US","Japan East","Japan West","North Central US","North Europe","South Central US","South India","Southeast Asia","West Europe","West US"]},"machineType":{"description":"Run load test using","ignoreCase":"all","enum":["0","2"]}},"additionalProperties":false,"required":["TestDrop"]}},"deprecationMessage":"ApacheJMeterLoadTest is deprecated - Run an Apache JMeter load test in the cloud","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Docker Compose\n\nBuild, push or run multi-container Docker applications. Task can be used with Docker or Azure Container registry.","ignoreCase":"value","pattern":"^DockerCompose@0$"},"inputs":{"description":"Docker Compose inputs","properties":{"containerregistrytype":{"description":"Container Registry Type","ignoreCase":"all","enum":["Azure Container Registry","Container Registry"]},"dockerRegistryEndpoint":{"type":"string","description":"Docker Registry Service Connection","ignoreCase":"key"},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["azureSubscriptionEndpoint"]},"azureContainerRegistry":{"type":"string","description":"Azure Container Registry","ignoreCase":"key"},"dockerComposeFile":{"type":"string","description":"Docker Compose File","ignoreCase":"key"},"additionalDockerComposeFiles":{"type":"string","description":"Additional Docker Compose Files","ignoreCase":"key"},"dockerComposeFileArgs":{"type":"string","description":"Environment Variables","ignoreCase":"key"},"projectName":{"type":"string","description":"Project Name","ignoreCase":"key"},"qualifyImageNames":{"type":"boolean","description":"Qualify Image Names","ignoreCase":"key"},"action":{"description":"Action","ignoreCase":"all","enum":["Build services","Push services","Run services","Run a specific service","Lock services","Write service image digests","Combine configuration","Run a Docker Compose command"]},"additionalImageTags":{"type":"string","description":"Additional Image Tags","ignoreCase":"key"},"includeSourceTags":{"type":"boolean","description":"Include Source Tags","ignoreCase":"key"},"includeLatestTag":{"type":"boolean","description":"Include Latest Tag","ignoreCase":"key"},"buildImages":{"type":"boolean","description":"Build Images","ignoreCase":"key"},"serviceName":{"type":"string","description":"Service Name","ignoreCase":"key"},"containerName":{"type":"string","description":"Container Name","ignoreCase":"key"},"ports":{"type":"string","description":"Ports","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["workDir"]},"entrypoint":{"type":"string","description":"Entry Point Override","ignoreCase":"key"},"containerCommand":{"type":"string","description":"Command","ignoreCase":"key"},"detached":{"type":"boolean","description":"Run in Background","ignoreCase":"key"},"abortOnContainerExit":{"type":"boolean","description":"Abort on Container Exit","ignoreCase":"key"},"imageDigestComposeFile":{"type":"string","description":"Image Digest Compose File","ignoreCase":"key"},"removeBuildOptions":{"type":"boolean","description":"Remove Build Options","ignoreCase":"key"},"baseResolveDirectory":{"type":"string","description":"Base Resolve Directory","ignoreCase":"key"},"outputDockerComposeFile":{"type":"string","description":"Output Docker Compose File","ignoreCase":"key"},"dockerComposeCommand":{"type":"string","description":"Command","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"dockerHostEndpoint":{"type":"string","description":"Docker Host Service Connection","ignoreCase":"key"},"nopIfNoDockerComposeFile":{"type":"boolean","description":"No-op if no Docker Compose File","ignoreCase":"key"},"requireAdditionalDockerComposeFiles":{"type":"boolean","description":"Require Additional Docker Compose Files","ignoreCase":"key"},"currentWorkingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["cwd"]},"dockerComposePath":{"type":"string","description":"Docker Compose executable Path","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure Monitor alerts (Deprecated)\n\nConfigure alerts on available metrics for an Azure resource (Deprecated)","ignoreCase":"value","pattern":"^AzureMonitorAlerts@0$"},"inputs":{"description":"Azure Monitor alerts (Deprecated) inputs","properties":{"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"ResourceGroupName":{"type":"string","description":"Resource Group","ignoreCase":"key"},"ResourceType":{"description":"Resource Type","ignoreCase":"all","enum":["Microsoft.Insights/components","Microsoft.Web/sites","Microsoft.Storage/storageAccounts","Microsoft.Compute/virtualMachines"]},"ResourceName":{"type":"string","description":"Resource name","ignoreCase":"key"},"AlertRules":{"type":"string","description":"Alert rules","ignoreCase":"key"},"NotifyServiceOwners":{"type":"boolean","description":"Subscription owners, contributors and readers","ignoreCase":"key"},"NotifyEmails":{"type":"string","description":"Additional administrator emails","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","ResourceGroupName","ResourceName","AlertRules"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Xamarin Test Cloud\n\n[Deprecated] Test mobile apps with Xamarin Test Cloud using Xamarin.UITest. Instead, use the 'App Center test' task.","ignoreCase":"value","pattern":"^XamarinTestCloud@1$"},"inputs":{"description":"Xamarin Test Cloud inputs","properties":{"appFile":{"type":"string","description":"App file","ignoreCase":"key","aliases":["app"]},"dsymFile":{"type":"string","description":"dSYM file (iOS only)","ignoreCase":"key","aliases":["dsym"]},"teamApiKey":{"type":"string","description":"Team API key","ignoreCase":"key"},"email":{"type":"string","description":"User email","ignoreCase":"key","aliases":["user"]},"devices":{"type":"string","description":"Devices","ignoreCase":"key"},"series":{"type":"string","description":"Series","ignoreCase":"key"},"testAssemblyDirectory":{"type":"string","description":"Test assembly directory","ignoreCase":"key","aliases":["testDir"]},"parallelizationOption":{"description":"Parallelization","ignoreCase":"all","enum":["none","--fixture-chunk","--test-chunk"],"aliases":["parallelization"]},"localeOption":{"description":"System language","ignoreCase":"all","enum":["da_DK","nl_NL","en_GB","en_US","fr_FR","de_DE","ja_JP","ru_RU","es_MX","es_ES","user"],"aliases":["locale"]},"userDefinedLocale":{"type":"string","description":"Other locale","ignoreCase":"key"},"testCloudFile":{"type":"string","description":"test-cloud.exe location","ignoreCase":"key","aliases":["testCloudLocation"]},"optionalArgs":{"type":"string","description":"Optional arguments","ignoreCase":"key"},"publishNUnitResults":{"type":"boolean","description":"Publish results to Azure Pipelines","ignoreCase":"key"}},"additionalProperties":false,"required":["appFile","teamApiKey","email","devices","testAssemblyDirectory"]}},"deprecationMessage":"XamarinTestCloud is deprecated - [Deprecated] Test mobile apps with Xamarin Test Cloud using Xamarin.UITest. Instead, use the 'App Center test' task.","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Service Fabric application deployment\n\nDeploy an Azure Service Fabric application to a cluster","ignoreCase":"value","pattern":"^ServiceFabricDeploy@1$"},"inputs":{"description":"Service Fabric application deployment inputs","properties":{"applicationPackagePath":{"type":"string","description":"Application Package","ignoreCase":"key"},"serviceConnectionName":{"type":"string","description":"Cluster Service Connection","ignoreCase":"key"},"publishProfilePath":{"type":"string","description":"Publish Profile","ignoreCase":"key"},"applicationParameterPath":{"type":"string","description":"Application Parameters","ignoreCase":"key"},"overrideApplicationParameter":{"type":"boolean","description":"Override Application Parameters","ignoreCase":"key"},"compressPackage":{"type":"boolean","description":"Compress Package","ignoreCase":"key"},"copyPackageTimeoutSec":{"type":"string","description":"CopyPackageTimeoutSec","ignoreCase":"key"},"registerPackageTimeoutSec":{"type":"string","description":"RegisterPackageTimeoutSec","ignoreCase":"key"},"overwriteBehavior":{"description":"Overwrite Behavior","ignoreCase":"all","enum":["Always","Never","SameAppTypeAndVersion"]},"skipUpgradeSameTypeAndVersion":{"type":"boolean","description":"Skip upgrade for same Type and Version","ignoreCase":"key"},"skipPackageValidation":{"type":"boolean","description":"Skip package validation","ignoreCase":"key"},"useDiffPackage":{"type":"boolean","description":"Use Diff Package","ignoreCase":"key"},"overridePublishProfileSettings":{"type":"boolean","description":"Override All Publish Profile Upgrade Settings","ignoreCase":"key"},"isUpgrade":{"type":"boolean","description":"Upgrade the Application","ignoreCase":"key"},"unregisterUnusedVersions":{"type":"boolean","description":"Unregister Unused Versions","ignoreCase":"key"},"upgradeMode":{"description":"Upgrade Mode","ignoreCase":"all","enum":["Monitored","UnmonitoredAuto","UnmonitoredManual"]},"FailureAction":{"description":"FailureAction","ignoreCase":"all","enum":["Rollback","Manual"]},"UpgradeReplicaSetCheckTimeoutSec":{"type":"string","description":"UpgradeReplicaSetCheckTimeoutSec","ignoreCase":"key"},"TimeoutSec":{"type":"string","description":"TimeoutSec","ignoreCase":"key"},"ForceRestart":{"type":"boolean","description":"ForceRestart","ignoreCase":"key"},"HealthCheckRetryTimeoutSec":{"type":"string","description":"HealthCheckRetryTimeoutSec","ignoreCase":"key"},"HealthCheckWaitDurationSec":{"type":"string","description":"HealthCheckWaitDurationSec","ignoreCase":"key"},"HealthCheckStableDurationSec":{"type":"string","description":"HealthCheckStableDurationSec","ignoreCase":"key"},"UpgradeDomainTimeoutSec":{"type":"string","description":"UpgradeDomainTimeoutSec","ignoreCase":"key"},"ConsiderWarningAsError":{"type":"boolean","description":"ConsiderWarningAsError","ignoreCase":"key"},"DefaultServiceTypeHealthPolicy":{"type":"string","description":"DefaultServiceTypeHealthPolicy","ignoreCase":"key"},"MaxPercentUnhealthyDeployedApplications":{"type":"string","description":"MaxPercentUnhealthyDeployedApplications","ignoreCase":"key"},"UpgradeTimeoutSec":{"type":"string","description":"UpgradeTimeoutSec","ignoreCase":"key"},"ServiceTypeHealthPolicyMap":{"type":"string","description":"ServiceTypeHealthPolicyMap","ignoreCase":"key"},"configureDockerSettings":{"type":"boolean","description":"Configure Docker settings","ignoreCase":"key"},"registryCredentials":{"description":"Registry Credentials Source","ignoreCase":"all","enum":["AzureResourceManagerEndpoint","ContainerRegistryEndpoint","UsernamePassword"]},"dockerRegistryConnection":{"type":"string","description":"Docker Registry Service Connection","ignoreCase":"key","aliases":["dockerRegistryEndpoint"]},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["azureSubscriptionEndpoint"]},"registryUserName":{"type":"string","description":"Registry User Name","ignoreCase":"key"},"registryPassword":{"type":"string","description":"Registry Password","ignoreCase":"key"},"passwordEncrypted":{"type":"boolean","description":"Password Encrypted","ignoreCase":"key"}},"additionalProperties":false,"required":["applicationPackagePath","serviceConnectionName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Cleanup\n\nUploads MicroBuild telemetry. This step should be added at the end of every definition using MicroBuild tasks.","ignoreCase":"value","pattern":"^MicroBuildCleanup@1$"},"inputs":{"description":"MicroBuild Cleanup inputs","properties":{},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild OptProf Plugin\n\nInstalls and configures the MicroBuild OptProf plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildOptProfPlugin@3$"},"inputs":{"description":"MicroBuild OptProf Plugin inputs","properties":{"optimizationDataDropName":{"type":"string","description":"OptimizationData Drop Name","ignoreCase":"key"},"optProfOutputPath":{"type":"string","description":"Optimization Data Output Path","ignoreCase":"key"},"skipRunOptimize":{"type":"boolean","description":"Generate Profile Data Without Optimization","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild OptProf Plugin\n\nInstalls and configures the MicroBuild OptProf plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildOptProfPlugin@2$"},"inputs":{"description":"MicroBuild OptProf Plugin inputs","properties":{"commitID":{"type":"string","description":"Commit ID","ignoreCase":"key"},"optProfOutputPath":{"type":"string","description":"Optimization Data Output Path","ignoreCase":"key"},"skipRunOptimize":{"type":"boolean","description":"Generate Profile Data Without Optimization","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild OptProf Plugin\n\nInstalls and configures the MicroBuild OptProf plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildOptProfPlugin@6$"},"inputs":{"description":"MicroBuild OptProf Plugin inputs","properties":{"ProfilingInputsDropName":{"type":"string","description":"Profiling Inputs Drop Name","ignoreCase":"key"},"GeneratePropsFile":{"type":"boolean","description":"Generate .props File","ignoreCase":"key"},"PropsPath":{"type":"string","description":".props File Path","ignoreCase":"key"},"ShouldSkipOptimize":{"type":"boolean","description":"Skip Optimization","ignoreCase":"key"},"OptimizationInputsLookupMethod":{"description":"Optimization Inputs Lookup Method","ignoreCase":"all","enum":["GitTag","DropPrefix","GitTagRepo","DropName"]},"DropNamePrefix":{"type":"string","description":"Drop Name Prefix","ignoreCase":"key"},"NumberCommitsToSearch":{"type":"string","description":"Number of Commits","ignoreCase":"key"},"GitTagProject":{"type":"string","description":"Project","ignoreCase":"key"},"GitTagRepo":{"type":"string","description":"Repository","ignoreCase":"key"},"GitTagBranch":{"type":"string","description":"Branch","ignoreCase":"key"},"OptimizationInputsDropName":{"type":"string","description":"Optimization Inputs Drop Name","ignoreCase":"key"},"OverrideOutputPath":{"type":"boolean","description":"Override Output Path","ignoreCase":"key"},"OptimizationOutputPath":{"type":"string","description":"Output Path","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"AccessToken":{"type":"string","description":"Drop Service Access Token","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild OptProf Plugin\n\nInstalls and configures the MicroBuild OptProf plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildOptProfPlugin@4$"},"inputs":{"description":"MicroBuild OptProf Plugin inputs","properties":{"optimizationInputsDropName":{"type":"string","description":"OptimizationInputs Drop Name","ignoreCase":"key"},"optimizationInputsDropNamePrefix":{"type":"string","description":"OptimizationInputs Drop Name Prefix","ignoreCase":"key"},"optProfOutputPath":{"type":"string","description":"Optimization Data Output Path","ignoreCase":"key"},"getDropNameByDrop":{"type":"boolean","description":"Get OptimizationInputs Drop by Querying the Azure DevOps Drop Directly.","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild OptProf Plugin\n\nInstalls and configures the MicroBuild OptProf plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildOptProfPlugin@5$"},"inputs":{"description":"MicroBuild OptProf Plugin inputs","properties":{"ProfilingInputsDropName":{"type":"string","description":"Profiling Inputs Drop Name","ignoreCase":"key"},"GeneratePropsFile":{"type":"boolean","description":"Generate .props File","ignoreCase":"key"},"PropsPath":{"type":"string","description":".props File Path","ignoreCase":"key"},"ShouldSkipOptimize":{"type":"boolean","description":"Skip Optimization","ignoreCase":"key"},"OptimizationInputsLookupMethod":{"description":"Optimization Inputs Lookup Method","ignoreCase":"all","enum":["GitTag","DropPrefix","GitTagRepo","DropName"]},"DropNamePrefix":{"type":"string","description":"Drop Name Prefix","ignoreCase":"key"},"GitTagProject":{"type":"string","description":"Project","ignoreCase":"key"},"GitTagRepo":{"type":"string","description":"Repository","ignoreCase":"key"},"GitTagBranch":{"type":"string","description":"Branch","ignoreCase":"key"},"OptimizationInputsDropName":{"type":"string","description":"Optimization Inputs Drop Name","ignoreCase":"key"},"OverrideOutputPath":{"type":"boolean","description":"Override Output Path","ignoreCase":"key"},"OptimizationOutputPath":{"type":"string","description":"Output Path","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild OptProf Plugin\n\nInstalls and configures the MicroBuild OptProf plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildOptProfPlugin@1$"},"inputs":{"description":"MicroBuild OptProf Plugin inputs","properties":{"commitID":{"type":"string","description":"Commit ID","ignoreCase":"key"},"optProfOutputPath":{"type":"string","description":"Optimization Data Output Path","ignoreCase":"key"},"skipRunOptimize":{"type":"boolean","description":"Generate Profile Data Without Optimization","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Xcode Build\n\nBuild an Xcode workspace on Mac OS","ignoreCase":"value","pattern":"^Xcode@2$"},"inputs":{"description":"Xcode Build inputs","properties":{"actions":{"type":"string","description":"Actions","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"sdk":{"type":"string","description":"SDK","ignoreCase":"key"},"xcWorkspacePath":{"type":"string","description":"Workspace/Project Path","ignoreCase":"key"},"scheme":{"type":"string","description":"Scheme","ignoreCase":"key"},"packageApp":{"type":"boolean","description":"Create App Package","ignoreCase":"key"},"packageTool":{"description":"Create Package (IPA) using","ignoreCase":"all","enum":["xcrun","xcodebuild"]},"archivePath":{"type":"string","description":"Archive Path","ignoreCase":"key"},"exportPath":{"type":"string","description":"Export Path","ignoreCase":"key"},"exportOptions":{"description":"Export Options","ignoreCase":"all","enum":["auto","plist","specify"]},"exportMethod":{"type":"string","description":"Export Method","ignoreCase":"key"},"exportTeamId":{"type":"string","description":"Team ID","ignoreCase":"key"},"exportOptionsPlist":{"type":"string","description":"Export Options Plist","ignoreCase":"key"},"xcode8AutomaticSigning":{"type":"boolean","description":"Automatic Signing","ignoreCase":"key"},"teamId":{"type":"string","description":"Team ID","ignoreCase":"key"},"signMethod":{"description":"Override Using","ignoreCase":"all","enum":["file","id"]},"iosSigningIdentity":{"type":"string","description":"Signing Identity","ignoreCase":"key"},"unlockDefaultKeychain":{"type":"boolean","description":"Unlock Default Keychain","ignoreCase":"key"},"defaultKeychainPassword":{"type":"string","description":"Default Keychain Password","ignoreCase":"key"},"provProfileUuid":{"type":"string","description":"Provisioning Profile UUID","ignoreCase":"key"},"p12":{"type":"string","description":"P12 Certificate File","ignoreCase":"key"},"p12pwd":{"type":"string","description":"P12 Password","ignoreCase":"key"},"provProfile":{"type":"string","description":"Provisioning Profile File","ignoreCase":"key"},"removeProfile":{"type":"boolean","description":"Remove Profile After Build","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"cwd":{"type":"string","description":"Working Directory","ignoreCase":"key"},"outputPattern":{"type":"string","description":"Output Directory","ignoreCase":"key"},"xcodeDeveloperDir":{"type":"string","description":"Xcode Developer Path","ignoreCase":"key"},"useXcpretty":{"type":"boolean","description":"Use xcpretty","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to VSTS/TFS","ignoreCase":"key"},"useXctool":{"type":"boolean","description":"Use xctool","ignoreCase":"key"},"xctoolReporter":{"type":"string","description":"xctool Test Reporter Format","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Xcode\n\nBuild, test, or archive an Xcode workspace on macOS. Optionally package an app.","ignoreCase":"value","pattern":"^Xcode@5$"},"inputs":{"description":"Xcode inputs","properties":{"actions":{"type":"string","description":"Actions","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"sdk":{"type":"string","description":"SDK","ignoreCase":"key"},"xcWorkspacePath":{"type":"string","description":"Workspace or project path","ignoreCase":"key"},"scheme":{"type":"string","description":"Scheme","ignoreCase":"key"},"xcodeVersion":{"description":"Xcode version","ignoreCase":"all","enum":["8","9","10","11","12","13","default","specifyPath"]},"xcodeDeveloperDir":{"type":"string","description":"Xcode developer path","ignoreCase":"key"},"packageApp":{"type":"boolean","description":"Create app package","ignoreCase":"key"},"archivePath":{"type":"string","description":"Archive path","ignoreCase":"key"},"exportPath":{"type":"string","description":"Export path","ignoreCase":"key"},"exportOptions":{"description":"Export options","ignoreCase":"all","enum":["auto","plist","specify"]},"exportMethod":{"type":"string","description":"Export method","ignoreCase":"key"},"exportTeamId":{"type":"string","description":"Team ID","ignoreCase":"key"},"exportOptionsPlist":{"type":"string","description":"Export options plist","ignoreCase":"key"},"exportArgs":{"type":"string","description":"Export arguments","ignoreCase":"key"},"signingOption":{"description":"Signing style","ignoreCase":"all","enum":["nosign","default","manual","auto"]},"signingIdentity":{"type":"string","description":"Signing identity","ignoreCase":"key"},"provisioningProfileUuid":{"type":"string","description":"Provisioning profile UUID","ignoreCase":"key"},"provisioningProfileName":{"type":"string","description":"Provisioning profile name","ignoreCase":"key"},"teamId":{"type":"string","description":"Team ID","ignoreCase":"key"},"destinationPlatformOption":{"description":"Destination platform","ignoreCase":"all","enum":["default","iOS","tvOS","macOS","custom"]},"destinationPlatform":{"type":"string","description":"Custom destination platform","ignoreCase":"key"},"destinationTypeOption":{"description":"Destination type","ignoreCase":"all","enum":["simulators","devices"]},"destinationSimulators":{"type":"string","description":"Simulator","ignoreCase":"key"},"destinationDevices":{"type":"string","description":"Device","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]},"useXcpretty":{"type":"boolean","description":"Use xcpretty","ignoreCase":"key"},"xcprettyArgs":{"type":"string","description":"Xcpretty arguments","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish test results to Azure Pipelines","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Xcode Build\n\nBuild an Xcode workspace on macOS","ignoreCase":"value","pattern":"^Xcode@3$"},"inputs":{"description":"Xcode Build inputs","properties":{"actions":{"type":"string","description":"Actions","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"sdk":{"type":"string","description":"SDK","ignoreCase":"key"},"xcWorkspacePath":{"type":"string","description":"Workspace/Project Path","ignoreCase":"key"},"scheme":{"type":"string","description":"Scheme","ignoreCase":"key"},"packageApp":{"type":"boolean","description":"Create App Package","ignoreCase":"key"},"archivePath":{"type":"string","description":"Archive Path","ignoreCase":"key"},"exportPath":{"type":"string","description":"Export Path","ignoreCase":"key"},"exportOptions":{"description":"Export Options","ignoreCase":"all","enum":["auto","plist","specify"]},"exportMethod":{"type":"string","description":"Export Method","ignoreCase":"key"},"exportTeamId":{"type":"string","description":"Team ID","ignoreCase":"key"},"exportOptionsPlist":{"type":"string","description":"Export Options Plist","ignoreCase":"key"},"exportArgs":{"type":"string","description":"Export Arguments","ignoreCase":"key"},"xcode8AutomaticSigning":{"type":"boolean","description":"Automatic Signing","ignoreCase":"key"},"teamId":{"type":"string","description":"Team ID","ignoreCase":"key"},"signMethod":{"description":"Override Using","ignoreCase":"all","enum":["file","id"]},"iosSigningIdentity":{"type":"string","description":"Signing Identity","ignoreCase":"key"},"unlockDefaultKeychain":{"type":"boolean","description":"Unlock Default Keychain","ignoreCase":"key"},"defaultKeychainPassword":{"type":"string","description":"Default Keychain Password","ignoreCase":"key"},"provProfileUuid":{"type":"string","description":"Provisioning Profile UUID","ignoreCase":"key"},"p12":{"type":"string","description":"P12 Certificate File","ignoreCase":"key"},"p12pwd":{"type":"string","description":"P12 Password","ignoreCase":"key"},"provProfile":{"type":"string","description":"Provisioning Profile File","ignoreCase":"key"},"removeProfile":{"type":"boolean","description":"Remove Profile After Build","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"cwd":{"type":"string","description":"Working Directory","ignoreCase":"key"},"outputPattern":{"type":"string","description":"Output Directory","ignoreCase":"key"},"xcodeDeveloperDir":{"type":"string","description":"Xcode Developer Path","ignoreCase":"key"},"useXcpretty":{"type":"boolean","description":"Use xcpretty","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to VSTS/TFS","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Xcode\n\nBuild, test, or archive an Xcode workspace on macOS. Optionally package an app.","ignoreCase":"value","pattern":"^Xcode@4$"},"inputs":{"description":"Xcode inputs","properties":{"actions":{"type":"string","description":"Actions","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"sdk":{"type":"string","description":"SDK","ignoreCase":"key"},"xcWorkspacePath":{"type":"string","description":"Workspace or project path","ignoreCase":"key"},"scheme":{"type":"string","description":"Scheme","ignoreCase":"key"},"xcodeVersion":{"description":"Xcode version","ignoreCase":"all","enum":["8","9","default","specifyPath"]},"xcodeDeveloperDir":{"type":"string","description":"Xcode developer path","ignoreCase":"key"},"packageApp":{"type":"boolean","description":"Create app package","ignoreCase":"key"},"archivePath":{"type":"string","description":"Archive path","ignoreCase":"key"},"exportPath":{"type":"string","description":"Export path","ignoreCase":"key"},"exportOptions":{"description":"Export options","ignoreCase":"all","enum":["auto","plist","specify"]},"exportMethod":{"type":"string","description":"Export method","ignoreCase":"key"},"exportTeamId":{"type":"string","description":"Team ID","ignoreCase":"key"},"exportOptionsPlist":{"type":"string","description":"Export options plist","ignoreCase":"key"},"exportArgs":{"type":"string","description":"Export arguments","ignoreCase":"key"},"signingOption":{"description":"Signing style","ignoreCase":"all","enum":["nosign","default","manual","auto"]},"signingIdentity":{"type":"string","description":"Signing identity","ignoreCase":"key"},"provisioningProfileUuid":{"type":"string","description":"Provisioning profile UUID","ignoreCase":"key"},"teamId":{"type":"string","description":"Team ID","ignoreCase":"key"},"destinationPlatformOption":{"description":"Destination platform","ignoreCase":"all","enum":["default","iOS","tvOS","macOS","custom"]},"destinationPlatform":{"type":"string","description":"Custom destination platform","ignoreCase":"key"},"destinationTypeOption":{"description":"Destination type","ignoreCase":"all","enum":["simulators","devices"]},"destinationSimulators":{"type":"string","description":"Simulator","ignoreCase":"key"},"destinationDevices":{"type":"string","description":"Device","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]},"outputPattern":{"type":"string","description":"Output directory","ignoreCase":"key"},"useXcpretty":{"type":"boolean","description":"Use xcpretty","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish test results to VSTS/TFS","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"NuGet publisher\n\nDeprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","ignoreCase":"value","pattern":"^NuGetPublisher@0$"},"inputs":{"description":"NuGet publisher inputs","properties":{"searchPattern":{"type":"string","description":"Path/Pattern to nupkg","ignoreCase":"key"},"nuGetFeedType":{"description":"Feed type","ignoreCase":"all","enum":["external","internal"]},"connectedServiceName":{"type":"string","description":"NuGet Service Connection","ignoreCase":"key"},"feedName":{"type":"string","description":"Internal Feed URL","ignoreCase":"key"},"nuGetAdditionalArgs":{"type":"string","description":"NuGet Arguments","ignoreCase":"key"},"verbosity":{"description":"Verbosity","ignoreCase":"all","enum":["-","Quiet","Normal","Detailed"]},"nuGetVersion":{"description":"NuGet Version","ignoreCase":"all","enum":["3.3.0","3.5.0.1829","4.0.0.2283","custom"]},"nuGetPath":{"type":"string","description":"Path to NuGet.exe","ignoreCase":"key"},"continueOnEmptyNupkgMatch":{"type":"boolean","description":"Continue if no packages match the \"Path/Pattern to nupkg\"","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"deprecationMessage":"NuGetPublisher is deprecated - Deprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","doNotSuggest":true,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Version Assemblies\n\nUpdates the version number of the assemblies to match the build number","ignoreCase":"value","pattern":"^VersionAssemblies@2$"},"inputs":{"description":"Version Assemblies inputs","properties":{"sourcePath":{"type":"string","description":"Source Path","ignoreCase":"key"},"filePattern":{"type":"string","description":"File Pattern","ignoreCase":"key"},"versionSource":{"description":"Version Source","ignoreCase":"all","enum":["buildNumber","variable"]},"customNumberVariable":{"type":"string","description":"Variable to use","ignoreCase":"key"},"versionFormat":{"description":"Version Extract Pattern","ignoreCase":"all","enum":["fourParts","threeParts","custom"]},"customBuildRegex":{"type":"string","description":"Custom Regex Find Pattern","ignoreCase":"key"},"replaceVersionFormat":{"description":"Replace Pattern","ignoreCase":"all","enum":["fourParts","threeParts","custom"]},"customReplaceRegex":{"type":"string","description":"Custom Regex Replace Pattern","ignoreCase":"key"},"buildRegexIndex":{"type":"string","description":"Build Regex Group Index","ignoreCase":"key"},"replacePrefix":{"type":"string","description":"Prefix for Replacements","ignoreCase":"key"},"replacePostfix":{"type":"string","description":"Postfix for Replacements","ignoreCase":"key"},"failIfNoMatchFound":{"type":"boolean","description":"Fail If No Target Match Found","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Query work items\n\nExecute a work item query and check the number of items returned","ignoreCase":"value","pattern":"^queryWorkItems@0$"},"inputs":{"description":"Query work items inputs","properties":{"queryId":{"type":"string","description":"Query","ignoreCase":"key"},"maxThreshold":{"type":"string","description":"Upper threshold","ignoreCase":"key"},"minThreshold":{"type":"string","description":"Lower threshold","ignoreCase":"key"}},"additionalProperties":false,"required":["queryId"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild IBCMerge Plugin\n\nInstalls and configures the MicroBuild IBCMerge plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildIBCMergePlugin@1$"},"inputs":{"description":"MicroBuild IBCMerge Plugin inputs","properties":{"branch":{"description":"Branch","ignoreCase":"all","enum":["master","rel/preview","svc/d15svc","svc/d15rtwsvc","rel/d15rel","lab/d15prerel","lab/vsumain","lab/vscore.dev","lab/vscore","lab/vsuvscore"]},"BuildNumber":{"type":"string","description":"Build number","ignoreCase":"key"},"SubPath":{"type":"string","description":"Data subdirectory","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"},"ShouldSkipPartialNgen":{"type":"boolean","description":"Disable PartialNgen","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild IBCMerge Plugin\n\nInstalls and configures the MicroBuild IBCMerge plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildIBCMergePlugin@0$"},"inputs":{"description":"MicroBuild IBCMerge Plugin inputs","properties":{"branch":{"description":"Branch","ignoreCase":"all","enum":["master","rel/preview","svc/d15svc","svc/d15rtwsvc","rel/d15rel","lab/d15prerel","lab/vsumain","lab/vscore.dev","lab/vscore","lab/vsuvscore"]},"BuildNumber":{"type":"string","description":"Build number","ignoreCase":"key"},"SubPath":{"type":"string","description":"Data subdirectory","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure Web App for Containers\n\nDeploy containers to Azure App Service","ignoreCase":"value","pattern":"^AzureWebAppContainer@1$"},"inputs":{"description":"Azure Web App for Containers inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"appName":{"type":"string","description":"App name","ignoreCase":"key"},"deployToSlotOrASE":{"type":"boolean","description":"Deploy to Slot or App Service Environment","ignoreCase":"key"},"resourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"slotName":{"type":"string","description":"Slot","ignoreCase":"key"},"containers":{"type":"string","description":"Image name","ignoreCase":"key","aliases":["imageName"]},"multicontainerConfigFile":{"type":"string","description":"Configuration File","ignoreCase":"key"},"containerCommand":{"type":"string","description":"Startup command ","ignoreCase":"key"},"appSettings":{"type":"string","description":"App settings","ignoreCase":"key"},"configurationStrings":{"type":"string","description":"Configuration settings","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","appName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"SQL Server database deploy\n\nDeploy a SQL Server database using DACPAC or SQL scripts","ignoreCase":"value","pattern":"^SqlDacpacDeploymentOnMachineGroup@0$"},"inputs":{"description":"SQL Server database deploy inputs","properties":{"TaskType":{"description":"Deploy SQL Using","ignoreCase":"all","enum":["dacpac","sqlQuery","sqlInline"]},"DacpacFile":{"type":"string","description":"DACPAC File","ignoreCase":"key"},"SqlFile":{"type":"string","description":"Sql File","ignoreCase":"key"},"ExecuteInTransaction":{"type":"boolean","description":"Execute within a transaction","ignoreCase":"key"},"ExclusiveLock":{"type":"boolean","description":"Acquire an exclusive app lock while executing script(s)","ignoreCase":"key"},"AppLockName":{"type":"string","description":"App lock name","ignoreCase":"key"},"InlineSql":{"type":"string","description":"Inline Sql","ignoreCase":"key"},"TargetMethod":{"description":"Specify SQL Using","ignoreCase":"all","enum":["server","connectionString","publishProfile"]},"ServerName":{"type":"string","description":"Server Name","ignoreCase":"key"},"DatabaseName":{"type":"string","description":"Database Name","ignoreCase":"key"},"AuthScheme":{"description":"Authentication","ignoreCase":"all","enum":["windowsAuthentication","sqlServerAuthentication"]},"SqlUsername":{"type":"string","description":"SQL User name","ignoreCase":"key"},"SqlPassword":{"type":"string","description":"SQL Password","ignoreCase":"key"},"ConnectionString":{"type":"string","description":"Connection String","ignoreCase":"key"},"PublishProfile":{"type":"string","description":"Publish Profile","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"},"AdditionalArgumentsSql":{"type":"string","description":"Additional Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Cache (Beta)\n\nCache files between runs","ignoreCase":"value","pattern":"^CacheBeta@1$"},"inputs":{"description":"Cache (Beta) inputs","properties":{"key":{"type":"string","description":"Key","ignoreCase":"key"},"path":{"type":"string","description":"Path","ignoreCase":"key"},"cacheHitVar":{"type":"string","description":"Cache hit variable","ignoreCase":"key"},"restoreKeys":{"type":"string","description":"Additional restore key prefixes","ignoreCase":"key"}},"additionalProperties":false,"required":["key","path"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Cache\n\nCache files between runs","ignoreCase":"value","pattern":"^Cache@2$"},"inputs":{"description":"Cache inputs","properties":{"key":{"type":"string","description":"Key","ignoreCase":"key"},"path":{"type":"string","description":"Path","ignoreCase":"key"},"cacheHitVar":{"type":"string","description":"Cache hit variable","ignoreCase":"key"},"restoreKeys":{"type":"string","description":"Additional restore key prefixes","ignoreCase":"key"}},"additionalProperties":false,"required":["key","path"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Cache (Beta)\n\nCache files between runs","ignoreCase":"value","pattern":"^CacheBeta@0$"},"inputs":{"description":"Cache (Beta) inputs","properties":{"key":{"type":"string","description":"Key","ignoreCase":"key"},"path":{"type":"string","description":"Path","ignoreCase":"key"},"cacheHitVar":{"type":"string","description":"Cache hit variable","ignoreCase":"key"}},"additionalProperties":false,"required":["key","path"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild FXCop Plugin\n\nInstalls and configures the MicroBuild FXCop plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildFXCopPlugin@2$"},"inputs":{"description":"MicroBuild FXCop Plugin inputs","properties":{"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"CMake\n\nBuild with the CMake cross-platform build system","ignoreCase":"value","pattern":"^CMake@1$"},"inputs":{"description":"CMake inputs","properties":{"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["cwd"]},"cmakeArgs":{"type":"string","description":"Arguments","ignoreCase":"key"},"runInsideShell":{"type":"boolean","description":"Run cmake command inside shell","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"App Center test\n\nTest app packages with Visual Studio App Center","ignoreCase":"value","pattern":"^AppCenterTest@1$"},"inputs":{"description":"App Center test inputs","properties":{"appFile":{"type":"string","description":"Binary application file path","ignoreCase":"key","aliases":["app"]},"artifactsDirectory":{"type":"string","description":"Artifacts directory","ignoreCase":"key","aliases":["artifactsDir"]},"prepareTests":{"type":"boolean","description":"Prepare tests","ignoreCase":"key","aliases":["enablePrepare"]},"frameworkOption":{"description":"Test framework","ignoreCase":"all","enum":["appium","espresso","calabash","uitest","xcuitest"],"aliases":["framework"]},"appiumBuildDirectory":{"type":"string","description":"Build directory","ignoreCase":"key","aliases":["appiumBuildDir"]},"espressoBuildDirectory":{"type":"string","description":"Build directory","ignoreCase":"key","aliases":["espressoBuildDir"]},"espressoTestApkFile":{"type":"string","description":"Test APK path","ignoreCase":"key","aliases":["espressoTestApkPath"]},"calabashProjectDirectory":{"type":"string","description":"Project directory","ignoreCase":"key","aliases":["calabashProjectDir"]},"calabashConfigFile":{"type":"string","description":"Cucumber config file","ignoreCase":"key"},"calabashProfile":{"type":"string","description":"Profile to run","ignoreCase":"key"},"calabashSkipConfigCheck":{"type":"boolean","description":"Skip Configuration Check","ignoreCase":"key"},"uiTestBuildDirectory":{"type":"string","description":"Build directory","ignoreCase":"key","aliases":["uitestBuildDir"]},"uitestStorePath":{"type":"string","description":"Store file","ignoreCase":"key"},"uiTestStorePassword":{"type":"string","description":"Store password","ignoreCase":"key","aliases":["uitestStorePass"]},"uitestKeyAlias":{"type":"string","description":"Key alias","ignoreCase":"key"},"uiTestKeyPassword":{"type":"string","description":"Key password","ignoreCase":"key","aliases":["uitestKeyPass"]},"uiTestToolsDirectory":{"type":"string","description":"Test tools directory","ignoreCase":"key","aliases":["uitestToolsDir"]},"signInfo":{"type":"string","description":"Signing information","ignoreCase":"key"},"xcUITestBuildDirectory":{"type":"string","description":"Build directory","ignoreCase":"key","aliases":["xcuitestBuildDir"]},"xcUITestIpaFile":{"type":"string","description":"Test IPA path","ignoreCase":"key","aliases":["xcuitestTestIpaPath"]},"prepareOptions":{"type":"string","description":"Additional options","ignoreCase":"key","aliases":["prepareOpts"]},"runTests":{"type":"boolean","description":"Run tests","ignoreCase":"key","aliases":["enableRun"]},"credentialsOption":{"description":"Authentication method","ignoreCase":"all","enum":["serviceEndpoint","inputs"],"aliases":["credsType"]},"serverEndpoint":{"type":"string","description":"App Center service connection","ignoreCase":"key"},"username":{"type":"string","description":"App Center username","ignoreCase":"key"},"password":{"type":"string","description":"App Center password","ignoreCase":"key"},"appSlug":{"type":"string","description":"App slug","ignoreCase":"key"},"devices":{"type":"string","description":"Devices","ignoreCase":"key"},"series":{"type":"string","description":"Test series","ignoreCase":"key"},"dsymDirectory":{"type":"string","description":"dSYM directory","ignoreCase":"key","aliases":["dsymDir"]},"localeOption":{"description":"System language","ignoreCase":"all","enum":["da_DK","nl_NL","en_GB","en_US","fr_FR","de_DE","ja_JP","ru_RU","es_MX","es_ES","user"],"aliases":["locale"]},"userDefinedLocale":{"type":"string","description":"Other locale","ignoreCase":"key"},"loginOptions":{"type":"string","description":"Additional options for login","ignoreCase":"key","aliases":["loginOpts"]},"runOptions":{"type":"string","description":"Additional options for run","ignoreCase":"key","aliases":["runOpts"]},"skipWaitingForResults":{"type":"boolean","description":"Do not wait for test result","ignoreCase":"key","aliases":["async"]},"cliFile":{"type":"string","description":"App Center CLI location","ignoreCase":"key","aliases":["cliLocationOverride"]},"showDebugOutput":{"type":"boolean","description":"Enable debug output","ignoreCase":"key","aliases":["debug"]}},"additionalProperties":false,"required":["appFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Mobile Center Test\n\nTest mobile app packages with Visual Studio Mobile Center.","ignoreCase":"value","pattern":"^VSMobileCenterTest@0$"},"inputs":{"description":"Mobile Center Test inputs","properties":{"app":{"type":"string","description":"Binary Application File Path","ignoreCase":"key"},"artifactsDir":{"type":"string","description":"Artifacts Directory","ignoreCase":"key"},"enablePrepare":{"type":"boolean","description":"Prepare Tests","ignoreCase":"key"},"framework":{"description":"Test Framework","ignoreCase":"all","enum":["appium","espresso","calabash","uitest","xcuitest"]},"appiumBuildDir":{"type":"string","description":"Build Directory","ignoreCase":"key"},"espressoBuildDir":{"type":"string","description":"Build Directory","ignoreCase":"key"},"espressoTestApkPath":{"type":"string","description":"Test APK Path","ignoreCase":"key"},"calabashProjectDir":{"type":"string","description":"Project Directory","ignoreCase":"key"},"calabashConfigFile":{"type":"string","description":"Cucumber Config File","ignoreCase":"key"},"calabashProfile":{"type":"string","description":"Profile to run","ignoreCase":"key"},"calabashSkipConfigCheck":{"type":"boolean","description":"Skip Configuration Check","ignoreCase":"key"},"uitestBuildDir":{"type":"string","description":"Build Directory","ignoreCase":"key"},"uitestStoreFile":{"type":"string","description":"Store File","ignoreCase":"key"},"uitestStorePass":{"type":"string","description":"Store Password","ignoreCase":"key"},"uitestKeyAlias":{"type":"string","description":"Key Alias","ignoreCase":"key"},"uitestKeyPass":{"type":"string","description":"Key Password","ignoreCase":"key"},"uitestToolsDir":{"type":"string","description":"Test Tools Directory","ignoreCase":"key"},"signInfo":{"type":"string","description":"Signing Information","ignoreCase":"key"},"xcuitestBuildDir":{"type":"string","description":"Build Directory","ignoreCase":"key"},"xcuitestTestIpaPath":{"type":"string","description":"Test IPA Path","ignoreCase":"key"},"prepareOpts":{"type":"string","description":"Additional Options","ignoreCase":"key"},"enableRun":{"type":"boolean","description":"Run Tests","ignoreCase":"key"},"credsType":{"description":"Authentication Method","ignoreCase":"all","enum":["serviceEndpoint","inputs"]},"serverEndpoint":{"type":"string","description":"Mobile Center Connection","ignoreCase":"key"},"username":{"type":"string","description":"Mobile Center Username","ignoreCase":"key"},"password":{"type":"string","description":"Mobile Center Password","ignoreCase":"key"},"appSlug":{"type":"string","description":"App Slug","ignoreCase":"key"},"devices":{"type":"string","description":"Devices","ignoreCase":"key"},"series":{"type":"string","description":"Test Series","ignoreCase":"key"},"dsymDir":{"type":"string","description":"dSYM Directory","ignoreCase":"key"},"locale":{"description":"System Language","ignoreCase":"all","enum":["da_DK","nl_NL","en_GB","en_US","fr_FR","de_DE","ja_JP","ru_RU","es_MX","es_ES","user"]},"userDefinedLocale":{"type":"string","description":"Other Locale","ignoreCase":"key"},"loginOpts":{"type":"string","description":"Addtional Options for Login","ignoreCase":"key"},"runOpts":{"type":"string","description":"Additional Options for Run","ignoreCase":"key"},"async":{"type":"boolean","description":"Do not wait for test result","ignoreCase":"key"},"cliLocationOverride":{"type":"string","description":"mobile-center CLI Location","ignoreCase":"key"},"debug":{"type":"boolean","description":"Enable Debug Output","ignoreCase":"key"}},"additionalProperties":false,"required":["app"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"EsrpClient Tool Installer\n\nFinds or Downloads and caches specified version spec of EsrpClient CLI and adds it to the PATH. In addition it will set esrpclient.toolpath and esrpclient.toolname task output variables which you can use in subsequent tasks or build scripts","ignoreCase":"value","pattern":"^EsrpClientTool@1$"},"inputs":{"description":"EsrpClient Tool Installer inputs","properties":{},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Download secure file\n\nDownload a secure file to the agent machine","ignoreCase":"value","pattern":"^DownloadSecureFile@1$"},"inputs":{"description":"Download secure file inputs","properties":{"secureFile":{"type":"string","description":"Secure File","ignoreCase":"key"},"retryCount":{"type":"string","description":"Retry Count","ignoreCase":"key"},"socketTimeout":{"type":"string","description":"Socket Timeout","ignoreCase":"key"}},"additionalProperties":false,"required":["secureFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Use Ruby version\n\nUse the specified version of Ruby from the tool cache, optionally adding it to the PATH","ignoreCase":"value","pattern":"^UseRubyVersion@0$"},"inputs":{"description":"Use Ruby version inputs","properties":{"versionSpec":{"type":"string","description":"Version spec","ignoreCase":"key"},"addToPath":{"type":"boolean","description":"Add to PATH","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Grunt\n\nRun the Grunt JavaScript task runner","ignoreCase":"value","pattern":"^Grunt@0$"},"inputs":{"description":"Grunt inputs","properties":{"gruntFile":{"type":"string","description":"Grunt File Path","ignoreCase":"key"},"targets":{"type":"string","description":"Grunt Task(s)","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["cwd"]},"gruntCli":{"type":"string","description":"grunt-cli location","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to Azure Pipelines","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test Results Files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test Run Title","ignoreCase":"key"},"enableCodeCoverage":{"type":"boolean","description":"Enable Code Coverage","ignoreCase":"key"},"testFramework":{"description":"Test Framework","ignoreCase":"all","enum":["Mocha","Jasmine"]},"srcFiles":{"type":"string","description":"Source Files","ignoreCase":"key"},"testFiles":{"type":"string","description":"Test Script Files","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure SQL Database deployment\n\nDeploy an Azure SQL Database using DACPAC or run scripts using SQLCMD","ignoreCase":"value","pattern":"^SqlAzureDacpacDeployment@1$"},"inputs":{"description":"Azure SQL Database deployment inputs","properties":{"azureConnectionType":{"description":"Azure Service Connection Type","ignoreCase":"all","enum":["ConnectedServiceName","ConnectedServiceNameARM"],"aliases":["ConnectedServiceNameSelector"]},"azureClassicSubscription":{"type":"string","description":"Azure Classic Subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceNameARM"]},"AuthenticationType":{"description":"Authentication Type","ignoreCase":"all","enum":["server","aadAuthenticationPassword","aadAuthenticationIntegrated","connectionString","servicePrincipal"]},"ServerName":{"type":"string","description":"Azure SQL Server","ignoreCase":"key"},"DatabaseName":{"type":"string","description":"Database","ignoreCase":"key"},"SqlUsername":{"type":"string","description":"Login","ignoreCase":"key"},"SqlPassword":{"type":"string","description":"Password","ignoreCase":"key"},"aadSqlUsername":{"type":"string","description":"Login","ignoreCase":"key"},"aadSqlPassword":{"type":"string","description":"Password","ignoreCase":"key"},"ConnectionString":{"type":"string","description":"Connection String","ignoreCase":"key"},"deployType":{"description":"Deploy type","ignoreCase":"all","enum":["DacpacTask","SqlTask","InlineSqlTask"],"aliases":["TaskNameSelector"]},"DeploymentAction":{"description":"Action","ignoreCase":"all","enum":["Publish","Extract","Export","Import","Script","DriftReport","DeployReport"]},"DacpacFile":{"type":"string","description":"DACPAC File","ignoreCase":"key"},"BacpacFile":{"type":"string","description":"BACPAC File","ignoreCase":"key"},"SqlFile":{"type":"string","description":"SQL Script","ignoreCase":"key"},"SqlInline":{"type":"string","description":"Inline SQL Script","ignoreCase":"key"},"PublishProfile":{"type":"string","description":"Publish Profile","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional SqlPackage.exe Arguments","ignoreCase":"key"},"SqlAdditionalArguments":{"type":"string","description":"Additional Invoke-Sqlcmd Arguments","ignoreCase":"key"},"InlineAdditionalArguments":{"type":"string","description":"Additional Invoke-Sqlcmd Arguments","ignoreCase":"key"},"IpDetectionMethod":{"description":"Specify Firewall Rules Using","ignoreCase":"all","enum":["AutoDetect","IPAddressRange"]},"StartIpAddress":{"type":"string","description":"Start IP Address","ignoreCase":"key"},"EndIpAddress":{"type":"string","description":"End IP Address","ignoreCase":"key"},"DeleteFirewallRule":{"type":"boolean","description":"Delete Rule After Task Ends","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Container Structure Test\n\nUses container-structure-test (https://github.com/GoogleContainerTools/container-structure-test) to validate the structure of an image based on four categories of tests - command tests, file existence tests, file content tests and metadata tests","ignoreCase":"value","pattern":"^ContainerStructureTest@0$"},"inputs":{"description":"Container Structure Test inputs","properties":{"dockerRegistryServiceConnection":{"type":"string","description":"Docker registry service connection","ignoreCase":"key"},"repository":{"type":"string","description":"Container repository","ignoreCase":"key"},"tag":{"type":"string","description":"Tag","ignoreCase":"key"},"configFile":{"type":"string","description":"Config file path","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"},"failTaskOnFailedTests":{"type":"boolean","description":"Fail task if there are test failures","ignoreCase":"key"}},"additionalProperties":false,"required":["dockerRegistryServiceConnection","repository","configFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"[Deprecated] IIS Web App deployment\n\nDeploy using MSDeploy, then create/update websites and app pools","ignoreCase":"value","pattern":"^IISWebAppDeployment@1$"},"inputs":{"description":"[Deprecated] IIS Web App deployment inputs","properties":{"EnvironmentName":{"type":"string","description":"Machines","ignoreCase":"key"},"AdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"AdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"WinRMProtocol":{"description":"Protocol","ignoreCase":"all","enum":["Http","Https"]},"TestCertificate":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"},"WebDeployPackage":{"type":"string","description":"Web Deploy Package","ignoreCase":"key"},"WebDeployParamFile":{"type":"string","description":"Web Deploy Parameter File","ignoreCase":"key"},"OverRideParams":{"type":"string","description":"Override Parameters","ignoreCase":"key"},"CreateWebSite":{"type":"boolean","description":"Create or Update Website","ignoreCase":"key"},"WebSiteName":{"type":"string","description":"Website Name","ignoreCase":"key"},"WebSitePhysicalPath":{"type":"string","description":"Physical Path","ignoreCase":"key"},"WebSitePhysicalPathAuth":{"description":"Physical Path Authentication","ignoreCase":"all","enum":["WebSiteUserPassThrough","WebSiteWindowsAuth"]},"WebSiteAuthUserName":{"type":"string","description":"User Name","ignoreCase":"key"},"WebSiteAuthUserPassword":{"type":"string","description":"Password","ignoreCase":"key"},"AddBinding":{"type":"boolean","description":"Add Binding","ignoreCase":"key"},"AssignDuplicateBinding":{"type":"boolean","description":"Assign Duplicate Binding","ignoreCase":"key"},"Protocol":{"description":"Protocol","ignoreCase":"all","enum":["https","http"]},"IPAddress":{"type":"string","description":"IP Address","ignoreCase":"key"},"Port":{"type":"string","description":"Port","ignoreCase":"key"},"ServerNameIndication":{"type":"boolean","description":"Server Name Indication Required","ignoreCase":"key"},"HostNameWithOutSNI":{"type":"string","description":"Host Name","ignoreCase":"key"},"HostNameWithHttp":{"type":"string","description":"Host Name","ignoreCase":"key"},"HostNameWithSNI":{"type":"string","description":"Host Name","ignoreCase":"key"},"SSLCertThumbPrint":{"type":"string","description":"SSL Certificate Thumb Print","ignoreCase":"key"},"CreateAppPool":{"type":"boolean","description":"Create or Update Application Pool","ignoreCase":"key"},"AppPoolName":{"type":"string","description":"Name","ignoreCase":"key"},"DotNetVersion":{"description":".NET Version","ignoreCase":"all","enum":["v4.0","v2.0","No Managed Code"]},"PipeLineMode":{"description":"Managed Pipeline Mode","ignoreCase":"all","enum":["Integrated","Classic"]},"AppPoolIdentity":{"description":"Identity","ignoreCase":"all","enum":["ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"]},"AppPoolUsername":{"type":"string","description":"Username","ignoreCase":"key"},"AppPoolPassword":{"type":"string","description":"Password","ignoreCase":"key"},"AppCmdCommands":{"type":"string","description":"Additional AppCmd.exe Commands","ignoreCase":"key"},"DeployInParallel":{"type":"boolean","description":"Deploy in Parallel","ignoreCase":"key"},"ResourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"MachineFilter":{"type":"string","description":"Deploy to Machines","ignoreCase":"key"}},"additionalProperties":false,"required":["EnvironmentName","WebDeployPackage"]}},"deprecationMessage":"IISWebAppDeployment is deprecated - Deploy using MSDeploy, then create/update websites and app pools","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Cloud-based load test\n\nRun a load test in the cloud with Azure Pipelines","ignoreCase":"value","pattern":"^CloudLoadTest@1$"},"inputs":{"description":"Cloud-based load test inputs","properties":{"connectedServiceName":{"type":"string","description":"Azure Pipelines Connection","ignoreCase":"key"},"TestDrop":{"type":"string","description":"Load test files folder","ignoreCase":"key"},"LoadTest":{"type":"string","description":"Load test file","ignoreCase":"key"},"activeRunSettings":{"description":"Active Run Settings","ignoreCase":"all","enum":["useFile","changeActive"]},"runSettingName":{"type":"string","description":"Specify the name of the Run Settings","ignoreCase":"key"},"testContextParameters":{"type":"string","description":"Override load test context parameters","ignoreCase":"key"},"TestSettings":{"type":"string","description":"Test settings file","ignoreCase":"key"},"ThresholdLimit":{"type":"string","description":"Number of permissible threshold violations","ignoreCase":"key"},"MachineType":{"description":"Run load test using","ignoreCase":"all","enum":["0","2"]},"resourceGroupName":{"type":"string","description":"Resource group rig","ignoreCase":"key"},"numOfSelfProvisionedAgents":{"type":"integer","description":"Number of agents to use","ignoreCase":"key"}},"additionalProperties":false,"required":["LoadTest"]}},"deprecationMessage":"CloudLoadTest is deprecated - Run a load test in the cloud with Azure Pipelines","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"1ES Hosted Pool Validation\n\nValidates that pipelines use secure and compliant Azure DevOps pools","ignoreCase":"value","pattern":"^1ESHostedPoolValidation@1$"},"inputs":{"description":"1ES Hosted Pool Validation inputs","properties":{},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Download Artifact Services Drop -preview\n\nDownload from Artifact Services Drop - Internal Preview","ignoreCase":"value","pattern":"^artifactDropDownloadTask@0$"},"inputs":{"description":"Download Artifact Services Drop -preview inputs","properties":{"dropMetadataContainerName":{"type":"string","description":"Drop Metadata Container Name","ignoreCase":"key"},"dropMetadataContainerBuild":{"type":"string","description":"Source Build of Drop Metadata Container","ignoreCase":"key"},"dropServiceURI":{"type":"string","description":"Drop Service Endpoint","ignoreCase":"key"},"buildNumber":{"type":"string","description":"Drop Name","ignoreCase":"key"},"destinationPath":{"type":"string","description":"Download Destination Path","ignoreCase":"key"},"rootPaths":{"type":"string","description":"Root Paths","ignoreCase":"key"},"writable":{"type":"boolean","description":"Make cache writable","ignoreCase":"key"},"dropExePath":{"type":"string","description":"Override drop.exe Path","ignoreCase":"key"},"detailedLog":{"type":"boolean","description":"Verbose Logging","ignoreCase":"key"},"usePat":{"type":"boolean","description":"Use Personal Access Token","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Kubectl tool installer\n\nInstall Kubectl on agent machine","ignoreCase":"value","pattern":"^KubectlInstaller@0$"},"inputs":{"description":"Kubectl tool installer inputs","properties":{"kubectlVersion":{"type":"string","description":"Kubectl Version Spec","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Command line\n\nRun a command line script using Bash on Linux and macOS and cmd.exe on Windows","ignoreCase":"value","pattern":"^CmdLine@2$"},"inputs":{"description":"Command line inputs","properties":{"script":{"type":"string","description":"Script","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key"},"failOnStderr":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Command Line\n\nRun a command line with arguments","ignoreCase":"value","pattern":"^CmdLine@1$"},"inputs":{"description":"Command Line inputs","properties":{"filename":{"type":"string","description":"Tool","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingFolder":{"type":"string","description":"Working folder","ignoreCase":"key"},"failOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"}},"additionalProperties":false,"required":["filename"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"NuGet command\n\nDeprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","ignoreCase":"value","pattern":"^NuGet@0$"},"inputs":{"description":"NuGet command inputs","properties":{"command":{"type":"string","description":"Command","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":["command"]}},"deprecationMessage":"NuGet is deprecated - Deprecated: use the “NuGet” task instead. It works with the new Tool Installer framework so you can easily use new versions of NuGet without waiting for a task update, provides better support for authenticated feeds outside this organization/collection, and uses NuGet 4 by default.","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Container Build\n\nContainer Build Task","ignoreCase":"value","pattern":"^ContainerBuild@0$"},"inputs":{"description":"Container Build inputs","properties":{"dockerRegistryServiceConnection":{"type":"string","description":"Docker registry service connection","ignoreCase":"key"},"repository":{"type":"string","description":"Container repository","ignoreCase":"key"},"Dockerfile":{"type":"string","description":"Dockerfile","ignoreCase":"key"},"buildContext":{"type":"string","description":"Build context","ignoreCase":"key"},"tags":{"type":"string","description":"Tags","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Send Helix End Telemetry\n\nSend end job telemetry for .NET Core builds","ignoreCase":"value","pattern":"^SendEndTelemetry@0$"},"inputs":{"description":"Send Helix End Telemetry inputs","properties":{"maxRetries":{"type":"string","description":"Maximum number of retry attempts","ignoreCase":"key"},"retryDelay":{"type":"string","description":"Number of seconds to wait between retry attempts","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"NuGet Restore\n\nRestores NuGet packages in preparation for a Visual Studio Build step.","ignoreCase":"value","pattern":"^NuGetRestore@1$"},"inputs":{"description":"NuGet Restore inputs","properties":{"solution":{"type":"string","description":"Path to solution, packages.config, or project.json","ignoreCase":"key"},"selectOrConfig":{"description":"Feeds to use","ignoreCase":"all","enum":["select","config"]},"feed":{"type":"string","description":"Use packages from this Azure Artifacts feed","ignoreCase":"key"},"includeNuGetOrg":{"type":"boolean","description":"Use packages from NuGet.org","ignoreCase":"key"},"nugetConfigPath":{"type":"string","description":"Path to NuGet.config","ignoreCase":"key"},"noCache":{"type":"boolean","description":"Disable local cache","ignoreCase":"key"},"packagesDirectory":{"type":"string","description":"Destination directory","ignoreCase":"key"},"verbosity":{"description":"Verbosity","ignoreCase":"all","enum":["-","Quiet","Normal","Detailed"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"NuGet\n\nRestore, pack, or push NuGet packages, or run a NuGet command. Supports NuGet.org and authenticated feeds like Azure Artifacts and MyGet. Uses NuGet.exe and works with .NET Framework apps. For .NET Core and .NET Standard apps, use the .NET Core task.","ignoreCase":"value","pattern":"^NuGetCommand@2$"},"inputs":{"description":"NuGet inputs","properties":{"command":{"description":"Command","ignoreCase":"all","enum":["restore","pack","push","custom"]},"restoreSolution":{"type":"string","description":"Path to solution, packages.config, or project.json","ignoreCase":"key","aliases":["solution"]},"feedsToUse":{"description":"Feeds to use","ignoreCase":"all","enum":["select","config"],"aliases":["selectOrConfig"]},"vstsFeed":{"type":"string","description":"Use packages from this Azure Artifacts/TFS feed","ignoreCase":"key","aliases":["feedRestore"]},"includeNuGetOrg":{"type":"boolean","description":"Use packages from NuGet.org","ignoreCase":"key"},"nugetConfigPath":{"type":"string","description":"Path to NuGet.config","ignoreCase":"key"},"externalFeedCredentials":{"type":"string","description":"Credentials for feeds outside this organization/collection","ignoreCase":"key","aliases":["externalEndpoints"]},"noCache":{"type":"boolean","description":"Disable local cache","ignoreCase":"key"},"disableParallelProcessing":{"type":"boolean","description":"Disable parallel processing","ignoreCase":"key"},"restoreDirectory":{"type":"string","description":"Destination directory","ignoreCase":"key","aliases":["packagesDirectory"]},"verbosityRestore":{"description":"Verbosity","ignoreCase":"all","enum":["Quiet","Normal","Detailed"]},"packagesToPush":{"type":"string","description":"Path to NuGet package(s) to publish","ignoreCase":"key","aliases":["searchPatternPush"]},"nuGetFeedType":{"description":"Target feed location","ignoreCase":"all","enum":["internal","external"]},"publishVstsFeed":{"type":"string","description":"Target feed","ignoreCase":"key","aliases":["feedPublish"]},"publishPackageMetadata":{"type":"boolean","description":"Publish pipeline metadata","ignoreCase":"key"},"allowPackageConflicts":{"type":"boolean","description":"Allow duplicates to be skipped","ignoreCase":"key"},"publishFeedCredentials":{"type":"string","description":"NuGet server","ignoreCase":"key","aliases":["externalEndpoint"]},"verbosityPush":{"description":"Verbosity","ignoreCase":"all","enum":["Quiet","Normal","Detailed"]},"packagesToPack":{"type":"string","description":"Path to csproj or nuspec file(s) to pack","ignoreCase":"key","aliases":["searchPatternPack"]},"configuration":{"type":"string","description":"Configuration to package","ignoreCase":"key","aliases":["configurationToPack"]},"packDestination":{"type":"string","description":"Package folder","ignoreCase":"key","aliases":["outputDir"]},"versioningScheme":{"description":"Automatic package versioning","ignoreCase":"all","enum":["off","byPrereleaseNumber","byEnvVar","byBuildNumber"]},"includeReferencedProjects":{"type":"boolean","description":"Include referenced projects","ignoreCase":"key"},"versionEnvVar":{"type":"string","description":"Environment variable","ignoreCase":"key"},"majorVersion":{"type":"string","description":"Major","ignoreCase":"key","aliases":["requestedMajorVersion"]},"minorVersion":{"type":"string","description":"Minor","ignoreCase":"key","aliases":["requestedMinorVersion"]},"patchVersion":{"type":"string","description":"Patch","ignoreCase":"key","aliases":["requestedPatchVersion"]},"packTimezone":{"description":"Time zone","ignoreCase":"all","enum":["utc","local"]},"includeSymbols":{"type":"boolean","description":"Create symbols package","ignoreCase":"key"},"toolPackage":{"type":"boolean","description":"Tool Package","ignoreCase":"key"},"buildProperties":{"type":"string","description":"Additional build properties","ignoreCase":"key"},"basePath":{"type":"string","description":"Base path","ignoreCase":"key"},"verbosityPack":{"description":"Verbosity","ignoreCase":"all","enum":["Quiet","Normal","Detailed"]},"arguments":{"type":"string","description":"Command and arguments","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"NuGet Installer\n\nInstalls or restores missing NuGet packages. Use NuGetAuthenticate@0 task for latest capabilities.","ignoreCase":"value","pattern":"^NuGetInstaller@0$"},"inputs":{"description":"NuGet Installer inputs","properties":{"solution":{"type":"string","description":"Path to solution or packages.config","ignoreCase":"key"},"nugetConfigPath":{"type":"string","description":"Path to NuGet.config","ignoreCase":"key"},"restoreMode":{"description":"Installation type","ignoreCase":"all","enum":["restore","install"]},"noCache":{"type":"boolean","description":"Disable local cache","ignoreCase":"key"},"nuGetRestoreArgs":{"type":"string","description":"NuGet arguments","ignoreCase":"key"},"verbosity":{"description":"Verbosity","ignoreCase":"all","enum":["-","Quiet","Normal","Detailed"]},"nuGetVersion":{"description":"NuGet Version","ignoreCase":"all","enum":["3.3.0","3.5.0.1829","4.0.0.2283","custom"]},"nuGetPath":{"type":"string","description":"Path to NuGet.exe","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"(deprecated) Docker Publish\n\nInvokes the VS Tools for Docker script with optional overrides","ignoreCase":"value","pattern":"^DockerPublish@0$"},"inputs":{"description":"(deprecated) Docker Publish inputs","properties":{"pathToPubxml":{"type":"string","description":"Path to Pubxml","ignoreCase":"key"},"pathToDockerfile":{"type":"string","description":"Path to Dockerfile","ignoreCase":"key"},"packOutput":{"type":"string","description":"Pack Output Path","ignoreCase":"key"},"serverUrl":{"type":"string","description":"Docker Server URL","ignoreCase":"key"},"imageName":{"type":"string","description":"Docker image name","ignoreCase":"key"},"buildOnly":{"type":"boolean","description":"Build only","ignoreCase":"key"},"hostPort":{"type":"string","description":"Host Port","ignoreCase":"key"},"containerPort":{"type":"string","description":"Container Port","ignoreCase":"key"},"runOptions":{"type":"string","description":"Run Options","ignoreCase":"key"},"appType":{"type":"string","description":"App Type","ignoreCase":"key"},"isWindowsContainer":{"type":"string","description":"Create Windows Container","ignoreCase":"key"},"authOptions":{"type":"string","description":"Auth Options","ignoreCase":"key"},"removeConflictingContainers":{"type":"string","description":"Remove Conflicting Containers","ignoreCase":"key"}},"additionalProperties":false,"required":["pathToDockerfile","packOutput"]}},"deprecationMessage":"DockerPublish is deprecated - Invokes the VS Tools for Docker script with optional overrides","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Delay\n\nDelay further execution of a workflow by a fixed time","ignoreCase":"value","pattern":"^Delay@1$"},"inputs":{"description":"Delay inputs","properties":{"delayForMinutes":{"type":"string","description":"Delay Time (minutes)","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Sign Mac Files\n\nSubmits Mac files to PRSS for signing","ignoreCase":"value","pattern":"^MicroBuildSignMacFiles@1$"},"inputs":{"description":"MicroBuild Sign Mac Files inputs","properties":{"SigningTarget":{"type":"string","description":"Folder or Zip or Dmg to Sign","ignoreCase":"key"},"SigningCert":{"description":"Signing Certificate","ignoreCase":"all","enum":["8001","8021","8003","8023","8020"]},"MacAppName":{"type":"string","description":"Mac Notarization App Name","ignoreCase":"key"},"SigningPluginSource":{"type":"string","description":"Signing Plugin Source","ignoreCase":"key"},"SigningPluginVersion":{"type":"string","description":"Signing Plugin Version","ignoreCase":"key"}},"additionalProperties":false,"required":["SigningTarget","SigningCert"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Sign Mac Files\n\nSubmits Mac files to PRSS for signing","ignoreCase":"value","pattern":"^MicroBuildSignMacFiles@0$"},"inputs":{"description":"MicroBuild Sign Mac Files inputs","properties":{"SigningTarget":{"type":"string","description":"Folder or Zip to Sign","ignoreCase":"key"},"SigningCert":{"description":"Signing Certificate","ignoreCase":"all","enum":["8001","8003"]},"SigningPluginSource":{"type":"string","description":"Signing Plugin Source","ignoreCase":"key"},"SigningPluginVersion":{"type":"string","description":"Signing Plugin Version","ignoreCase":"key"}},"additionalProperties":false,"required":["SigningTarget","SigningCert"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Xamarin.iOS\n\nBuild an iOS app with Xamarin on macOS","ignoreCase":"value","pattern":"^XamariniOS@2$"},"inputs":{"description":"Xamarin.iOS inputs","properties":{"solutionFile":{"type":"string","description":"Solution","ignoreCase":"key","aliases":["solution"]},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"clean":{"type":"boolean","description":"Clean","ignoreCase":"key"},"packageApp":{"type":"boolean","description":"Create app package","ignoreCase":"key"},"buildForSimulator":{"type":"boolean","description":"Build for iOS Simulator","ignoreCase":"key","aliases":["forSimulator"]},"runNugetRestore":{"type":"boolean","description":"Run NuGet restore","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]},"mdtoolFile":{"type":"string","description":"Build tool path","ignoreCase":"key","aliases":["buildToolLocation","mdtoolLocation"]},"signingIdentity":{"type":"string","description":"Signing identity","ignoreCase":"key","aliases":["iosSigningIdentity"]},"signingProvisioningProfileID":{"type":"string","description":"Provisioning profile UUID","ignoreCase":"key","aliases":["provProfileUuid"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Xamarin.iOS\n\nBuild an iOS app with Xamarin on macOS","ignoreCase":"value","pattern":"^XamariniOS@1$"},"inputs":{"description":"Xamarin.iOS inputs","properties":{"solutionFile":{"type":"string","description":"Solution","ignoreCase":"key","aliases":["solution"]},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"clean":{"type":"boolean","description":"Clean","ignoreCase":"key"},"packageApp":{"type":"boolean","description":"Create app package","ignoreCase":"key"},"buildForSimulator":{"type":"boolean","description":"Build for iOS Simulator","ignoreCase":"key","aliases":["forSimulator"]},"runNugetRestore":{"type":"boolean","description":"Run NuGet restore","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]},"buildToolOption":{"description":"Build tool","ignoreCase":"all","enum":["xbuild","msbuild"],"aliases":["buildTool"]},"mdtoolFile":{"type":"string","description":"Build tool path","ignoreCase":"key","aliases":["mdtoolLocation"]},"signingOption":{"description":"Override using","ignoreCase":"all","enum":["file","id"],"aliases":["signMethod"]},"signingIdentity":{"type":"string","description":"Signing identity","ignoreCase":"key","aliases":["iosSigningIdentity"]},"signingUnlockDefaultKeychain":{"type":"boolean","description":"Unlock default keychain","ignoreCase":"key","aliases":["unlockDefaultKeychain"]},"signingDefaultKeychainPassword":{"type":"string","description":"Default keychain password","ignoreCase":"key","aliases":["defaultKeychainPassword"]},"signingProvisioningProfileID":{"type":"string","description":"Provisioning profile UUID","ignoreCase":"key","aliases":["provProfileUuid"]},"signingP12File":{"type":"string","description":"P12 certificate file","ignoreCase":"key","aliases":["p12"]},"signingP12Password":{"type":"string","description":"P12 password","ignoreCase":"key","aliases":["p12pwd"]},"signingProvisioningProfileFile":{"type":"string","description":"Provisioning profile file","ignoreCase":"key","aliases":["provProfile"]},"signingRemoveProfile":{"type":"boolean","description":"Remove profile after build","ignoreCase":"key","aliases":["removeProfile"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Ref12 Analyze\n\nAnalyze repository and generate data files to enable semantic code browsing.","ignoreCase":"value","pattern":"^Ref12Analyze@0$"},"inputs":{"description":"Ref12 Analyze inputs","properties":{"codexoutputroot":{"type":"string","description":"Codex Output Root","ignoreCase":"key"},"workflowArguments":{"type":"string","description":"Workflow Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Publish test results\n\nPublish test results to Azure Pipelines","ignoreCase":"value","pattern":"^PublishTestResults@1$"},"inputs":{"description":"Publish test results inputs","properties":{"testRunner":{"description":"Test Result Format","ignoreCase":"all","enum":["JUnit","NUnit","VSTest","XUnit"]},"testResultsFiles":{"type":"string","description":"Test Results Files","ignoreCase":"key"},"mergeTestResults":{"type":"boolean","description":"Merge Test Results","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test Run Title","ignoreCase":"key"},"platform":{"type":"string","description":"Platform","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"publishRunAttachments":{"type":"boolean","description":"Upload Test Attachments","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Publish Test Results\n\nPublish test results to Azure Pipelines","ignoreCase":"value","pattern":"^PublishTestResults@2$"},"inputs":{"description":"Publish Test Results inputs","properties":{"testResultsFormat":{"description":"Test result format","ignoreCase":"all","enum":["JUnit","NUnit","VSTest","XUnit","CTest"],"aliases":["testRunner"]},"testResultsFiles":{"type":"string","description":"Test results files","ignoreCase":"key"},"searchFolder":{"type":"string","description":"Search folder","ignoreCase":"key"},"mergeTestResults":{"type":"boolean","description":"Merge test results","ignoreCase":"key"},"failTaskOnFailedTests":{"type":"boolean","description":"Fail if there are test failures","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"},"buildPlatform":{"type":"string","description":"Build Platform","ignoreCase":"key","aliases":["platform"]},"buildConfiguration":{"type":"string","description":"Build Configuration","ignoreCase":"key","aliases":["configuration"]},"publishRunAttachments":{"type":"boolean","description":"Upload test results files","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure file copy\n\nCopy files to Azure Blob Storage or virtual machines","ignoreCase":"value","pattern":"^AzureFileCopy@1$"},"inputs":{"description":"Azure file copy inputs","properties":{"SourcePath":{"type":"string","description":"Source","ignoreCase":"key"},"azureConnectionType":{"description":"Azure Connection Type","ignoreCase":"all","enum":["ConnectedServiceName","ConnectedServiceNameARM"],"aliases":["ConnectedServiceNameSelector"]},"azureClassicSubscription":{"type":"string","description":"Azure Classic Subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceNameARM"]},"Destination":{"description":"Destination Type","ignoreCase":"all","enum":["AzureBlob","AzureVMs"]},"classicStorage":{"type":"string","description":"Classic Storage Account","ignoreCase":"key","aliases":["StorageAccount"]},"storage":{"type":"string","description":"RM Storage Account","ignoreCase":"key","aliases":["StorageAccountRM"]},"ContainerName":{"type":"string","description":"Container Name","ignoreCase":"key"},"BlobPrefix":{"type":"string","description":"Blob Prefix","ignoreCase":"key"},"cloudService":{"type":"string","description":"Cloud Service","ignoreCase":"key","aliases":["EnvironmentName"]},"resourceGroup":{"type":"string","description":"Resource Group","ignoreCase":"key","aliases":["EnvironmentNameRM"]},"ResourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"MachineNames":{"type":"string","description":"Filter Criteria","ignoreCase":"key"},"vmsAdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"vmsAdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"TargetPath":{"type":"string","description":"Destination Folder","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"},"enableCopyPrerequisites":{"type":"boolean","description":"Enable Copy Prerequisites","ignoreCase":"key"},"CopyFilesInParallel":{"type":"boolean","description":"Copy in Parallel","ignoreCase":"key"},"CleanTargetBeforeCopy":{"type":"boolean","description":"Clean Target","ignoreCase":"key"},"skipCACheck":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"},"outputStorageUri":{"type":"string","description":"Storage Container URI","ignoreCase":"key"},"outputStorageContainerSasToken":{"type":"string","description":"Storage Container SAS Token","ignoreCase":"key"}},"additionalProperties":false,"required":["SourcePath","Destination"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure file copy\n\nCopy files to Azure Blob Storage or virtual machines","ignoreCase":"value","pattern":"^AzureFileCopy@2$"},"inputs":{"description":"Azure file copy inputs","properties":{"SourcePath":{"type":"string","description":"Source","ignoreCase":"key"},"azureConnectionType":{"description":"Azure Connection Type","ignoreCase":"all","enum":["ConnectedServiceName","ConnectedServiceNameARM"],"aliases":["ConnectedServiceNameSelector"]},"azureClassicSubscription":{"type":"string","description":"Azure Classic Subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceNameARM"]},"Destination":{"description":"Destination Type","ignoreCase":"all","enum":["AzureBlob","AzureVMs"]},"classicStorage":{"type":"string","description":"Classic Storage Account","ignoreCase":"key","aliases":["StorageAccount"]},"storage":{"type":"string","description":"RM Storage Account","ignoreCase":"key","aliases":["StorageAccountRM"]},"ContainerName":{"type":"string","description":"Container Name","ignoreCase":"key"},"BlobPrefix":{"type":"string","description":"Blob Prefix","ignoreCase":"key"},"cloudService":{"type":"string","description":"Cloud Service","ignoreCase":"key","aliases":["EnvironmentName"]},"resourceGroup":{"type":"string","description":"Resource Group","ignoreCase":"key","aliases":["EnvironmentNameRM"]},"ResourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"MachineNames":{"type":"string","description":"Filter Criteria","ignoreCase":"key"},"vmsAdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"vmsAdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"TargetPath":{"type":"string","description":"Destination Folder","ignoreCase":"key"},"AdditionalArgumentsForBlobCopy":{"type":"string","description":"Optional Arguments (for uploading files to blob)","ignoreCase":"key"},"AdditionalArgumentsForVMCopy":{"type":"string","description":"Optional Arguments (for downloading files to VM)","ignoreCase":"key"},"enableCopyPrerequisites":{"type":"boolean","description":"Enable Copy Prerequisites","ignoreCase":"key"},"CopyFilesInParallel":{"type":"boolean","description":"Copy in Parallel","ignoreCase":"key"},"CleanTargetBeforeCopy":{"type":"boolean","description":"Clean Target","ignoreCase":"key"},"skipCACheck":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"},"outputStorageUri":{"type":"string","description":"Storage Container URI","ignoreCase":"key"},"outputStorageContainerSasToken":{"type":"string","description":"Storage Container SAS Token","ignoreCase":"key"}},"additionalProperties":false,"required":["SourcePath","Destination"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure file copy\n\nCopy files to Azure Blob Storage or virtual machines","ignoreCase":"value","pattern":"^AzureFileCopy@3$"},"inputs":{"description":"Azure file copy inputs","properties":{"SourcePath":{"type":"string","description":"Source","ignoreCase":"key"},"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceNameARM"]},"Destination":{"description":"Destination Type","ignoreCase":"all","enum":["AzureBlob","AzureVMs"]},"storage":{"type":"string","description":"RM Storage Account","ignoreCase":"key","aliases":["StorageAccountRM"]},"ContainerName":{"type":"string","description":"Container Name","ignoreCase":"key"},"BlobPrefix":{"type":"string","description":"Blob Prefix","ignoreCase":"key"},"resourceGroup":{"type":"string","description":"Resource Group","ignoreCase":"key","aliases":["EnvironmentNameRM"]},"ResourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"MachineNames":{"type":"string","description":"Filter Criteria","ignoreCase":"key"},"vmsAdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"vmsAdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"TargetPath":{"type":"string","description":"Destination Folder","ignoreCase":"key"},"AdditionalArgumentsForBlobCopy":{"type":"string","description":"Optional Arguments (for uploading files to blob)","ignoreCase":"key"},"AdditionalArgumentsForVMCopy":{"type":"string","description":"Optional Arguments (for downloading files to VM)","ignoreCase":"key"},"enableCopyPrerequisites":{"type":"boolean","description":"Enable Copy Prerequisites","ignoreCase":"key"},"CopyFilesInParallel":{"type":"boolean","description":"Copy in Parallel","ignoreCase":"key"},"CleanTargetBeforeCopy":{"type":"boolean","description":"Clean Target","ignoreCase":"key"},"skipCACheck":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"},"outputStorageUri":{"type":"string","description":"Storage Container URI","ignoreCase":"key"},"outputStorageContainerSasToken":{"type":"string","description":"Storage Container SAS Token","ignoreCase":"key"},"sasTokenTimeOutInMinutes":{"type":"string","description":"SAS Token Expiration Period In Minutes","ignoreCase":"key"}},"additionalProperties":false,"required":["SourcePath","azureSubscription","Destination","storage"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure file copy\n\nCopy files to Azure Blob Storage or virtual machines","ignoreCase":"value","pattern":"^AzureFileCopy@4$"},"inputs":{"description":"Azure file copy inputs","properties":{"SourcePath":{"type":"string","description":"Source","ignoreCase":"key"},"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceNameARM"]},"Destination":{"description":"Destination Type","ignoreCase":"all","enum":["AzureBlob","AzureVMs"]},"storage":{"type":"string","description":"RM Storage Account","ignoreCase":"key","aliases":["StorageAccountRM"]},"ContainerName":{"type":"string","description":"Container Name","ignoreCase":"key"},"BlobPrefix":{"type":"string","description":"Blob Prefix","ignoreCase":"key"},"resourceGroup":{"type":"string","description":"Resource Group","ignoreCase":"key","aliases":["EnvironmentNameRM"]},"ResourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"MachineNames":{"type":"string","description":"Filter Criteria","ignoreCase":"key"},"vmsAdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"vmsAdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"TargetPath":{"type":"string","description":"Destination Folder","ignoreCase":"key"},"AdditionalArgumentsForBlobCopy":{"type":"string","description":"Optional Arguments (for uploading files to blob)","ignoreCase":"key"},"AdditionalArgumentsForVMCopy":{"type":"string","description":"Optional Arguments (for downloading files to VM)","ignoreCase":"key"},"sasTokenTimeOutInMinutes":{"type":"string","description":"SAS Token Expiration Period In Minutes","ignoreCase":"key"},"enableCopyPrerequisites":{"type":"boolean","description":"Enable Copy Prerequisites","ignoreCase":"key"},"CopyFilesInParallel":{"type":"boolean","description":"Copy in Parallel","ignoreCase":"key"},"CleanTargetBeforeCopy":{"type":"boolean","description":"Clean Target","ignoreCase":"key"},"skipCACheck":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"}},"additionalProperties":false,"required":["SourcePath","azureSubscription","Destination","storage"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Swix Plugin\n\nInstalls and configures the MicroBuild swix plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildSwixPlugin@3$"},"inputs":{"description":"MicroBuild Swix Plugin inputs","properties":{"dropName":{"type":"string","description":"Drop Name","ignoreCase":"key"},"dropServiceUri":{"type":"string","description":"VSDrop Service Uri","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Swix Plugin\n\nInstalls and configures the MicroBuild swix plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildSwixPlugin@4$"},"inputs":{"description":"MicroBuild Swix Plugin inputs","properties":{"dropName":{"type":"string","description":"Drop Name","ignoreCase":"key"},"dropServiceUri":{"type":"string","description":"VSDrop Service Uri","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Swix Plugin\n\nInstalls and configures the MicroBuild swix plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildSwixPlugin@2$"},"inputs":{"description":"MicroBuild Swix Plugin inputs","properties":{"dropName":{"type":"string","description":"Drop Name","ignoreCase":"key"},"dropServiceUri":{"type":"string","description":"VSDrop Service Uri","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Swix Plugin\n\nInstalls and configures the MicroBuild swix plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildSwixPlugin@1$"},"inputs":{"description":"MicroBuild Swix Plugin inputs","properties":{"dropName":{"type":"string","description":"Drop Name","ignoreCase":"key"},"dropServiceUri":{"type":"string","description":"VSDrop Service Uri","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Index sources and publish symbols\n\nIndex your source code and publish symbols to a file share or Azure Artifacts symbol server","ignoreCase":"value","pattern":"^PublishSymbols@2$"},"inputs":{"description":"Index sources and publish symbols inputs","properties":{"SymbolsFolder":{"type":"string","description":"Path to symbols folder","ignoreCase":"key"},"SearchPattern":{"type":"string","description":"Search pattern","ignoreCase":"key"},"IndexSources":{"type":"boolean","description":"Index sources","ignoreCase":"key"},"PublishSymbols":{"type":"boolean","description":"Publish symbols","ignoreCase":"key"},"SymbolServerType":{"description":"Symbol server type","ignoreCase":"all","enum":[" ","TeamServices","FileShare"]},"SymbolsPath":{"type":"string","description":"Path to publish symbols","ignoreCase":"key"},"CompressSymbols":{"type":"boolean","description":"Compress symbols","ignoreCase":"key"},"IndexableFileFormats":{"description":"Symbol file formats to publish","ignoreCase":"all","enum":["Default","Pdb","SourceMap","All"]},"DetailedLog":{"type":"boolean","description":"Verbose logging","ignoreCase":"key"},"TreatNotIndexedAsWarning":{"type":"boolean","description":"Warn if not indexed","ignoreCase":"key"},"SymbolsMaximumWaitTime":{"type":"string","description":"Max wait time (min)","ignoreCase":"key"},"SymbolsProduct":{"type":"string","description":"Product","ignoreCase":"key"},"SymbolsVersion":{"type":"string","description":"Version","ignoreCase":"key"},"SymbolsArtifactName":{"type":"string","description":"Artifact name","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Index Sources & Publish Symbols\n\nIndex your source code and publish symbols to a file share","ignoreCase":"value","pattern":"^PublishSymbols@1$"},"inputs":{"description":"Index Sources & Publish Symbols inputs","properties":{"SymbolsPath":{"type":"string","description":"Path to publish symbols","ignoreCase":"key"},"SearchPattern":{"type":"string","description":"Search pattern","ignoreCase":"key"},"SymbolsFolder":{"type":"string","description":"Path to symbols folder","ignoreCase":"key"},"SkipIndexing":{"type":"boolean","description":"Skip indexing","ignoreCase":"key"},"TreatNotIndexedAsWarning":{"type":"boolean","description":"Warn if not indexed","ignoreCase":"key"},"SymbolsMaximumWaitTime":{"type":"string","description":"Max wait time (min)","ignoreCase":"key"},"SymbolsProduct":{"type":"string","description":"Product","ignoreCase":"key"},"SymbolsVersion":{"type":"string","description":"Version","ignoreCase":"key"},"SymbolsArtifactName":{"type":"string","description":"Artifact name","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Copy files over SSH\n\nCopy files or build artifacts to a remote machine over SSH","ignoreCase":"value","pattern":"^CopyFilesOverSSH@0$"},"inputs":{"description":"Copy files over SSH inputs","properties":{"sshEndpoint":{"type":"string","description":"SSH service connection","ignoreCase":"key"},"sourceFolder":{"type":"string","description":"Source folder","ignoreCase":"key"},"contents":{"type":"string","description":"Contents","ignoreCase":"key"},"targetFolder":{"type":"string","description":"Target folder","ignoreCase":"key"},"isWindowsOnTarget":{"type":"boolean","description":"Target machine running Windows","ignoreCase":"key"},"cleanTargetFolder":{"type":"boolean","description":"Clean target folder","ignoreCase":"key"},"readyTimeout":{"type":"string","description":"SSH handshake timeout","ignoreCase":"key"},"overwrite":{"type":"boolean","description":"Overwrite","ignoreCase":"key"},"failOnEmptySource":{"type":"boolean","description":"Fail if no files found to copy","ignoreCase":"key"},"flattenFolders":{"type":"boolean","description":"Flatten folders","ignoreCase":"key"}},"additionalProperties":false,"required":["sshEndpoint"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Gradle\n\nBuild using a Gradle wrapper script","ignoreCase":"value","pattern":"^Gradle@2$"},"inputs":{"description":"Gradle inputs","properties":{"gradleWrapperFile":{"type":"string","description":"Gradle wrapper","ignoreCase":"key","aliases":["wrapperScript"]},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]},"options":{"type":"string","description":"Options","ignoreCase":"key"},"tasks":{"type":"string","description":"Tasks","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to Azure Pipelines","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test results files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"},"codeCoverageToolOption":{"description":"Code coverage tool","ignoreCase":"all","enum":["None","Cobertura","JaCoCo"],"aliases":["codeCoverageTool"]},"codeCoverageClassFilesDirectories":{"type":"string","description":"Class files directories","ignoreCase":"key","aliases":["classFilesDirectories"]},"codeCoverageClassFilter":{"type":"string","description":"Class inclusion/exclusion filters","ignoreCase":"key","aliases":["classFilter"]},"codeCoverageFailIfEmpty":{"type":"boolean","description":"Fail when code coverage results are missing","ignoreCase":"key","aliases":["failIfCoverageEmpty"]},"codeCoverageGradle5xOrHigher":{"type":"boolean","description":"Gradle version >= 5.x","ignoreCase":"key","aliases":["gradle5xOrHigher"]},"javaHomeOption":{"description":"Set JAVA_HOME by","ignoreCase":"all","enum":["JDKVersion","Path"],"aliases":["javaHomeSelection"]},"jdkVersionOption":{"description":"JDK version","ignoreCase":"all","enum":["default","1.11","1.10","1.9","1.8","1.7","1.6"],"aliases":["jdkVersion"]},"jdkDirectory":{"type":"string","description":"JDK path","ignoreCase":"key","aliases":["jdkUserInputPath"]},"jdkArchitectureOption":{"description":"JDK architecture","ignoreCase":"all","enum":["x86","x64"],"aliases":["jdkArchitecture"]},"gradleOptions":{"type":"string","description":"Set GRADLE_OPTS","ignoreCase":"key","aliases":["gradleOpts"]},"sonarQubeRunAnalysis":{"type":"boolean","description":"Run SonarQube or SonarCloud Analysis","ignoreCase":"key","aliases":["sqAnalysisEnabled"]},"sqGradlePluginVersionChoice":{"description":"SonarQube scanner for Gradle version","ignoreCase":"all","enum":["specify","build"]},"sonarQubeGradlePluginVersion":{"type":"string","description":"SonarQube scanner for Gradle plugin version","ignoreCase":"key","aliases":["sqGradlePluginVersion"]},"checkStyleRunAnalysis":{"type":"boolean","description":"Run Checkstyle","ignoreCase":"key","aliases":["checkstyleAnalysisEnabled"]},"findBugsRunAnalysis":{"type":"boolean","description":"Run FindBugs","ignoreCase":"key","aliases":["findbugsAnalysisEnabled"]},"pmdRunAnalysis":{"type":"boolean","description":"Run PMD","ignoreCase":"key","aliases":["pmdAnalysisEnabled"]},"spotBugsAnalysis":{"type":"boolean","description":"Run SpotBugs","ignoreCase":"key","aliases":["spotBugsAnalysisEnabled"]},"spotBugsGradlePluginVersionChoice":{"description":"Spotbugs plugin version","ignoreCase":"all","enum":["specify","build"]},"spotbugsGradlePluginVersion":{"type":"string","description":"Version number","ignoreCase":"key","aliases":["spotbugsGradlePluginVersion"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Gradle\n\nBuild using a Gradle wrapper script","ignoreCase":"value","pattern":"^Gradle@3$"},"inputs":{"description":"Gradle inputs","properties":{"gradleWrapperFile":{"type":"string","description":"Gradle wrapper","ignoreCase":"key","aliases":["wrapperScript"]},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]},"options":{"type":"string","description":"Options","ignoreCase":"key"},"tasks":{"type":"string","description":"Tasks","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to Azure Pipelines","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test results files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"},"codeCoverageToolOption":{"description":"Code coverage tool","ignoreCase":"all","enum":["None","Cobertura","JaCoCo"],"aliases":["codeCoverageTool"]},"codeCoverageClassFilesDirectories":{"type":"string","description":"Class files directories","ignoreCase":"key","aliases":["classFilesDirectories"]},"codeCoverageClassFilter":{"type":"string","description":"Class inclusion/exclusion filters","ignoreCase":"key","aliases":["classFilter"]},"codeCoverageFailIfEmpty":{"type":"boolean","description":"Fail when code coverage results are missing","ignoreCase":"key","aliases":["failIfCoverageEmpty"]},"codeCoverageGradle5xOrHigher":{"type":"boolean","description":"Gradle version >= 5.x","ignoreCase":"key","aliases":["gradle5xOrHigher"]},"javaHomeOption":{"description":"Set JAVA_HOME by","ignoreCase":"all","enum":["JDKVersion","Path"],"aliases":["javaHomeSelection"]},"jdkVersionOption":{"description":"JDK version","ignoreCase":"all","enum":["default","1.11","1.10","1.9","1.8","1.7","1.6"],"aliases":["jdkVersion"]},"jdkDirectory":{"type":"string","description":"JDK path","ignoreCase":"key","aliases":["jdkUserInputPath"]},"jdkArchitectureOption":{"description":"JDK architecture","ignoreCase":"all","enum":["x86","x64"],"aliases":["jdkArchitecture"]},"gradleOptions":{"type":"string","description":"Set GRADLE_OPTS","ignoreCase":"key","aliases":["gradleOpts"]},"sonarQubeRunAnalysis":{"type":"boolean","description":"Run SonarQube or SonarCloud Analysis","ignoreCase":"key","aliases":["sqAnalysisEnabled"]},"sqGradlePluginVersionChoice":{"description":"SonarQube scanner for Gradle version","ignoreCase":"all","enum":["specify","build"]},"sonarQubeGradlePluginVersion":{"type":"string","description":"SonarQube scanner for Gradle plugin version","ignoreCase":"key","aliases":["sqGradlePluginVersion"]},"checkStyleRunAnalysis":{"type":"boolean","description":"Run Checkstyle","ignoreCase":"key","aliases":["checkstyleAnalysisEnabled"]},"findBugsRunAnalysis":{"type":"boolean","description":"Run FindBugs","ignoreCase":"key","aliases":["findbugsAnalysisEnabled"]},"pmdRunAnalysis":{"type":"boolean","description":"Run PMD","ignoreCase":"key","aliases":["pmdAnalysisEnabled"]},"spotBugsAnalysis":{"type":"boolean","description":"Run SpotBugs","ignoreCase":"key","aliases":["spotBugsAnalysisEnabled"]},"spotBugsGradlePluginVersionChoice":{"description":"Spotbugs plugin version","ignoreCase":"all","enum":["specify","build"]},"spotbugsGradlePluginVersion":{"type":"string","description":"Version number","ignoreCase":"key","aliases":["spotbugsGradlePluginVersion"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Gradle\n\nBuild using a Gradle wrapper script","ignoreCase":"value","pattern":"^Gradle@1$"},"inputs":{"description":"Gradle inputs","properties":{"gradleWrapperFile":{"type":"string","description":"Gradle Wrapper","ignoreCase":"key","aliases":["wrapperScript"]},"options":{"type":"string","description":"Options","ignoreCase":"key"},"tasks":{"type":"string","description":"Tasks","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["cwd"]},"publishJUnitResults":{"type":"boolean","description":"Publish to TFS/Team Services","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test Results Files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test Run Title","ignoreCase":"key"},"codeCoverageToolOption":{"description":"Code Coverage Tool","ignoreCase":"all","enum":["None","Cobertura","JaCoCo"],"aliases":["codeCoverageTool"]},"codeCoverageClassFilesDirectories":{"type":"string","description":"Class Files Directories","ignoreCase":"key","aliases":["classFilesDirectories"]},"codeCoverageClassFilter":{"type":"string","description":"Class Inclusion/Exclusion Filters","ignoreCase":"key","aliases":["classFilter"]},"codeCoverageFailIfEmpty":{"type":"boolean","description":"Fail When Code Coverage Results Are Missing","ignoreCase":"key","aliases":["failIfCoverageEmpty"]},"javaHomeOption":{"description":"Set JAVA_HOME by","ignoreCase":"all","enum":["JDKVersion","Path"],"aliases":["javaHomeSelection"]},"jdkVersionOption":{"description":"JDK Version","ignoreCase":"all","enum":["default","1.9","1.8","1.7","1.6"],"aliases":["jdkVersion"]},"jdkDirectory":{"type":"string","description":"JDK Path","ignoreCase":"key","aliases":["jdkUserInputPath"]},"jdkArchitectureOption":{"description":"JDK Architecture","ignoreCase":"all","enum":["x86","x64"],"aliases":["jdkArchitecture"]},"gradleOptions":{"type":"string","description":"Set GRADLE_OPTS","ignoreCase":"key","aliases":["gradleOpts"]},"sonarQubeRunAnalysis":{"type":"boolean","description":"Run SonarQube Analysis","ignoreCase":"key","aliases":["sqAnalysisEnabled"]},"sonarQubeServiceEndpoint":{"type":"string","description":"SonarQube Endpoint","ignoreCase":"key","aliases":["sqConnectedServiceName"]},"sonarQubeProjectName":{"type":"string","description":"SonarQube Project Name","ignoreCase":"key","aliases":["sqProjectName"]},"sonarQubeProjectKey":{"type":"string","description":"SonarQube Project Key","ignoreCase":"key","aliases":["sqProjectKey"]},"sonarQubeProjectVersion":{"type":"string","description":"SonarQube Project Version","ignoreCase":"key","aliases":["sqProjectVersion"]},"sonarQubeGradlePluginVersion":{"type":"string","description":"SonarQube Gradle Plugin Version","ignoreCase":"key","aliases":["sqGradlePluginVersion"]},"sonarQubeSpecifyDB":{"type":"boolean","description":"The SonarQube server version is lower than 5.2","ignoreCase":"key","aliases":["sqDbDetailsRequired"]},"sonarQubeDBUrl":{"type":"string","description":"Db Connection String","ignoreCase":"key","aliases":["sqDbUrl"]},"sonarQubeDBUsername":{"type":"string","description":"Db Username","ignoreCase":"key","aliases":["sqDbUsername"]},"sonarQubeDBPassword":{"type":"string","description":"Db User Password","ignoreCase":"key","aliases":["sqDbPassword"]},"sonarQubeIncludeFullReport":{"type":"boolean","description":"Include full analysis report in the build summary (SQ 5.3+)","ignoreCase":"key","aliases":["sqAnalysisIncludeFullReport"]},"sonarQubeFailWhenQualityGateFails":{"type":"boolean","description":"Fail the build on quality gate failure (SQ 5.3+)","ignoreCase":"key","aliases":["sqAnalysisBreakBuildIfQualityGateFailed"]},"checkStyleRunAnalysis":{"type":"boolean","description":"Run Checkstyle","ignoreCase":"key","aliases":["checkstyleAnalysisEnabled"]},"findBugsRunAnalysis":{"type":"boolean","description":"Run FindBugs","ignoreCase":"key","aliases":["findbugsAnalysisEnabled"]},"pmdRunAnalysis":{"type":"boolean","description":"Run PMD","ignoreCase":"key","aliases":["pmdAnalysisEnabled"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Replace Tokens\n\nReplaces tokens in a file using RegEx. Values come from any variable defined in the current Environment.","ignoreCase":"value","pattern":"^ReplaceTokens@1$"},"inputs":{"description":"Replace Tokens inputs","properties":{"sourcePath":{"type":"string","description":"Source Path","ignoreCase":"key"},"filePattern":{"type":"string","description":"Target File Pattern","ignoreCase":"key"},"warningsAsErrors":{"type":"boolean","description":"Treat warnings as errors","ignoreCase":"key"},"tokenRegex":{"type":"string","description":"Token Regex","ignoreCase":"key"},"secretTokens":{"type":"string","description":"Secret Tokens (only for TFS 2015)","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Localization Plugin\n\nInstalls and configures the MicroBuild localization plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildLocalizationPlugin@1$"},"inputs":{"description":"MicroBuild Localization Plugin inputs","properties":{"type":{"description":"Localization Type","ignoreCase":"all","enum":["full","hybrid","pseudo"]},"languages":{"type":"string","description":"Languages","ignoreCase":"key"},"manifestPath":{"type":"string","description":"Manifest File (Deprecated)","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Localization Plugin\n\nInstalls and configures the MicroBuild localization plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildLocalizationPlugin@4$"},"inputs":{"description":"MicroBuild Localization Plugin inputs","properties":{"type":{"description":"Localization Type","ignoreCase":"all","enum":["full","hybrid","pseudo"]},"languages":{"type":"string","description":"Languages","ignoreCase":"key"},"lsbuildVersion":{"description":"LSBuild Version","ignoreCase":"all","enum":["V7","V6"]},"manifestPath":{"type":"string","description":"Manifest File (Deprecated)","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Localization Plugin\n\nInstalls and configures the MicroBuild localization plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildLocalizationPlugin@3$"},"inputs":{"description":"MicroBuild Localization Plugin inputs","properties":{"type":{"description":"Localization Type","ignoreCase":"all","enum":["full","hybrid","pseudo"]},"languages":{"type":"string","description":"Languages","ignoreCase":"key"},"manifestPath":{"type":"string","description":"Manifest File (Deprecated)","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Localization Plugin\n\nInstalls and configures the MicroBuild localization plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildLocalizationPlugin@2$"},"inputs":{"description":"MicroBuild Localization Plugin inputs","properties":{"type":{"description":"Localization Type","ignoreCase":"all","enum":["full","hybrid","pseudo"]},"languages":{"type":"string","description":"Languages","ignoreCase":"key"},"manifestPath":{"type":"string","description":"Manifest File (Deprecated)","ignoreCase":"key"},"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"ESRP Malware Scanning\n\nMicrosoft Internal tool for Malware Scanning of files using ESRP Service","ignoreCase":"value","pattern":"^EsrpMalwareScanning@1$"},"inputs":{"description":"ESRP Malware Scanning inputs","properties":{"ConnectedServiceName":{"type":"string","description":"Connection Name","ignoreCase":"key"},"FolderPath":{"type":"string","description":"Root folder path to get input files for scanning","ignoreCase":"key"},"Pattern":{"type":"string","description":"File search pattern to discover to be scanned files inside Root Folder Path variable above","ignoreCase":"key"},"UseMinimatch":{"type":"boolean","description":"Use Minimatch","ignoreCase":"key"},"Region":{"description":"Datacenter","ignoreCase":"all","enum":["PuertoRico","US"]},"SessionTimeout":{"type":"string","description":"Max Session Time (minutes)","ignoreCase":"key"},"ServiceEndpointUrl":{"type":"string","description":"API Endpoint Url","ignoreCase":"key"},"MaxConcurrency":{"type":"string","description":"Max Concurrency","ignoreCase":"key"},"MaxRetryAttempts":{"type":"string","description":"Max Retry Attempts","ignoreCase":"key"},"CleanupTempStorage":{"type":"boolean","description":"Cleanup all temp blob storage","ignoreCase":"key"},"VerboseLogin":{"type":"boolean","description":"Verbose Logs","ignoreCase":"key"},"tlsVersion":{"description":"TLS Version","ignoreCase":"all","enum":["Tls","Tls11","Tls12"]}},"additionalProperties":false,"required":["ConnectedServiceName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"App Center distribute\n\nDistribute app builds to testers and users via Visual Studio App Center","ignoreCase":"value","pattern":"^AppCenterDistribute@1$"},"inputs":{"description":"App Center distribute inputs","properties":{"serverEndpoint":{"type":"string","description":"App Center service connection","ignoreCase":"key"},"appSlug":{"type":"string","description":"App slug","ignoreCase":"key"},"appFile":{"type":"string","description":"Binary file path","ignoreCase":"key","aliases":["app"]},"symbolsOption":{"description":"Symbols type","ignoreCase":"all","enum":["Apple"],"aliases":["symbolsType"]},"symbolsPath":{"type":"string","description":"Symbols path","ignoreCase":"key"},"symbolsPdbFiles":{"type":"string","description":"Symbols path (*.pdb)","ignoreCase":"key","aliases":["pdbPath"]},"symbolsDsymFiles":{"type":"string","description":"dSYM path","ignoreCase":"key","aliases":["dsymPath"]},"symbolsMappingTxtFile":{"type":"string","description":"Mapping file","ignoreCase":"key","aliases":["mappingTxtPath"]},"symbolsIncludeParentDirectory":{"type":"boolean","description":"Include all items in parent folder","ignoreCase":"key","aliases":["packParentFolder"]},"releaseNotesOption":{"description":"Create release notes","ignoreCase":"all","enum":["input","file"],"aliases":["releaseNotesSelection"]},"releaseNotesInput":{"type":"string","description":"Release notes","ignoreCase":"key"},"releaseNotesFile":{"type":"string","description":"Release notes file","ignoreCase":"key"},"isMandatory":{"type":"boolean","description":"Require users to update to this release","ignoreCase":"key"},"distributionGroupId":{"type":"string","description":"Destination ID","ignoreCase":"key","aliases":["destinationId"]}},"additionalProperties":false,"required":["serverEndpoint","appSlug","appFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"App Center distribute\n\nDistribute app builds to testers and users via Visual Studio App Center","ignoreCase":"value","pattern":"^AppCenterDistribute@2$"},"inputs":{"description":"App Center distribute inputs","properties":{"serverEndpoint":{"type":"string","description":"App Center service connection","ignoreCase":"key"},"appSlug":{"type":"string","description":"App slug","ignoreCase":"key"},"appFile":{"type":"string","description":"Binary file path","ignoreCase":"key","aliases":["app"]},"symbolsOption":{"description":"Symbols type","ignoreCase":"all","enum":["Apple"],"aliases":["symbolsType"]},"symbolsPath":{"type":"string","description":"Symbols path","ignoreCase":"key"},"symbolsPdbFiles":{"type":"string","description":"Symbols path (*.pdb)","ignoreCase":"key","aliases":["pdbPath"]},"symbolsDsymFiles":{"type":"string","description":"dSYM path","ignoreCase":"key","aliases":["dsymPath"]},"symbolsMappingTxtFile":{"type":"string","description":"Mapping file","ignoreCase":"key","aliases":["mappingTxtPath"]},"symbolsIncludeParentDirectory":{"type":"boolean","description":"Include all items in parent folder","ignoreCase":"key","aliases":["packParentFolder"]},"releaseNotesOption":{"description":"Create release notes","ignoreCase":"all","enum":["input","file"],"aliases":["releaseNotesSelection"]},"releaseNotesInput":{"type":"string","description":"Release notes","ignoreCase":"key"},"releaseNotesFile":{"type":"string","description":"Release notes file","ignoreCase":"key"},"isMandatory":{"type":"boolean","description":"Require users to update to this release","ignoreCase":"key"},"distributionGroupId":{"type":"string","description":"Destination IDs","ignoreCase":"key","aliases":["destinationIds","destinationId"]}},"additionalProperties":false,"required":["serverEndpoint","appSlug","appFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"App Center distribute\n\nDistribute app builds to testers and users via Visual Studio App Center","ignoreCase":"value","pattern":"^AppCenterDistribute@3$"},"inputs":{"description":"App Center distribute inputs","properties":{"serverEndpoint":{"type":"string","description":"App Center service connection","ignoreCase":"key"},"appSlug":{"type":"string","description":"App slug","ignoreCase":"key"},"appFile":{"type":"string","description":"Binary file path","ignoreCase":"key","aliases":["app"]},"buildVersion":{"type":"string","description":"Build version","ignoreCase":"key"},"symbolsOption":{"description":"Symbols type","ignoreCase":"all","enum":["Apple","Android","UWP"],"aliases":["symbolsType"]},"symbolsPath":{"type":"string","description":"Symbols path","ignoreCase":"key"},"appxsymPath":{"type":"string","description":"Symbols path (*.appxsym)","ignoreCase":"key"},"symbolsDsymFiles":{"type":"string","description":"dSYM path","ignoreCase":"key","aliases":["dsymPath"]},"symbolsMappingTxtFile":{"type":"string","description":"Mapping file","ignoreCase":"key","aliases":["mappingTxtPath"]},"nativeLibrariesPath":{"type":"string","description":"Native Library File Path","ignoreCase":"key"},"symbolsIncludeParentDirectory":{"type":"boolean","description":"Include all items in parent folder","ignoreCase":"key","aliases":["packParentFolder"]},"releaseNotesOption":{"description":"Create release notes","ignoreCase":"all","enum":["input","file"],"aliases":["releaseNotesSelection"]},"releaseNotesInput":{"type":"string","description":"Release notes","ignoreCase":"key"},"releaseNotesFile":{"type":"string","description":"Release notes file","ignoreCase":"key"},"isMandatory":{"type":"boolean","description":"Require users to update to this release","ignoreCase":"key"},"destinationType":{"description":"Release destination","ignoreCase":"all","enum":["groups","store"]},"distributionGroupId":{"type":"string","description":"Destination IDs","ignoreCase":"key","aliases":["destinationGroupIds"]},"destinationStoreId":{"type":"string","description":"Destination ID","ignoreCase":"key"},"isSilent":{"type":"boolean","description":"Do not notify testers. Release will still be available to install.","ignoreCase":"key"}},"additionalProperties":false,"required":["serverEndpoint","appSlug","appFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"App Center Distribute\n\nDistribute app builds to testers and users via App Center","ignoreCase":"value","pattern":"^AppCenterDistribute@0$"},"inputs":{"description":"App Center Distribute inputs","properties":{"serverEndpoint":{"type":"string","description":"App Center connection","ignoreCase":"key"},"appSlug":{"type":"string","description":"App slug","ignoreCase":"key"},"appFile":{"type":"string","description":"Binary file path","ignoreCase":"key","aliases":["app"]},"symbolsOption":{"description":"Symbols type","ignoreCase":"all","enum":["Apple"],"aliases":["symbolsType"]},"symbolsPath":{"type":"string","description":"Symbols path","ignoreCase":"key"},"symbolsPdbFiles":{"type":"string","description":"Symbols path (*.pdb)","ignoreCase":"key","aliases":["pdbPath"]},"symbolsDsymFiles":{"type":"string","description":"dSYM path","ignoreCase":"key","aliases":["dsymPath"]},"symbolsMappingTxtFile":{"type":"string","description":"Mapping file","ignoreCase":"key","aliases":["mappingTxtPath"]},"symbolsIncludeParentDirectory":{"type":"boolean","description":"Include all items in parent folder","ignoreCase":"key","aliases":["packParentFolder"]},"releaseNotesOption":{"description":"Create release notes","ignoreCase":"all","enum":["input","file"],"aliases":["releaseNotesSelection"]},"releaseNotesInput":{"type":"string","description":"Release notes","ignoreCase":"key"},"releaseNotesFile":{"type":"string","description":"Release notes file","ignoreCase":"key"},"distributionGroupId":{"type":"string","description":"Distribution group ID","ignoreCase":"key"}},"additionalProperties":false,"required":["serverEndpoint","appSlug","appFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"NuGet tool installer\n\nAcquires a specific version of NuGet from the internet or the tools cache and adds it to the PATH. Use this task to change the version of NuGet used in the NuGet tasks.","ignoreCase":"value","pattern":"^NuGetToolInstaller@1$"},"inputs":{"description":"NuGet tool installer inputs","properties":{"versionSpec":{"type":"string","description":"Version of NuGet.exe to install","ignoreCase":"key"},"checkLatest":{"type":"boolean","description":"Always check for new versions","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"NuGet tool installer\n\nAcquires a specific version of NuGet from the internet or the tools cache and adds it to the PATH. Use this task to change the version of NuGet used in the NuGet tasks.","ignoreCase":"value","pattern":"^NuGetToolInstaller@0$"},"inputs":{"description":"NuGet tool installer inputs","properties":{"versionSpec":{"type":"string","description":"Version of NuGet.exe to install","ignoreCase":"key"},"checkLatest":{"type":"boolean","description":"Always download the latest matching version","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"(deprecated) Azure Web Deploy\n\nInvokes web deploy to Azure website, substituting any Environment variables into the SetParameters.xml file","ignoreCase":"value","pattern":"^AzureWebDeploy@0$"},"inputs":{"description":"(deprecated) Azure Web Deploy inputs","properties":{"ConnectedServiceName":{"type":"string","description":"Azure Subscription","ignoreCase":"key"},"WebSiteName":{"type":"string","description":"Web App Name","ignoreCase":"key"},"WebSiteLocation":{"description":"Web App Location","ignoreCase":"all","enum":["Australia East","Australia Southeast","Brazil South","Central US","East Asia","East US","East US2","Japan East","Japan West","North Central US","North Europe","South Central US","Southeast Asia","West Europe","West US"]},"Slot":{"type":"string","description":"Slot","ignoreCase":"key"},"PackagePath":{"type":"string","description":"Web Deploy Package Path","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":["ConnectedServiceName","WebSiteName","PackagePath"]}},"deprecationMessage":"AzureWebDeploy is deprecated - Invokes web deploy to Azure website, substituting any Environment variables into the SetParameters.xml file","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"OneLocBuild\n\nGeneric LSBuild wrapper which streamlines the localization build process and optionally checks-in resulting localized files to a repo","ignoreCase":"value","pattern":"^OneLocBuild@2$"},"inputs":{"description":"OneLocBuild inputs","properties":{"locProj":{"type":"string","description":"Localization Project","ignoreCase":"key"},"outDir":{"type":"string","description":"Output Directory","ignoreCase":"key"},"lclSource":{"description":"LCL Source","ignoreCase":"all","enum":["lclFilesInRepo","lclFilesfromPackage"]},"lclPackageId":{"type":"string","description":"LCL Package ID","ignoreCase":"key"},"lclPackageVersion":{"description":"LCL Package Version","ignoreCase":"all","enum":["highestLclPackageVersion","lclPackageVersionSetByVariable"]},"lclPackageVersionVariable":{"type":"string","description":"Variable for LCL Package Version","ignoreCase":"key"},"isEnablePseudoLanguagesSelected":{"type":"boolean","description":"Enable localization for pseudo languages","ignoreCase":"key"},"isCreatePrSelected":{"type":"boolean","description":"Create a pull request to check-in localized files to the repo","ignoreCase":"key"},"repoType":{"description":"Repo Type","ignoreCase":"all","enum":["azureReposGit","gitHub"]},"prSourceBranchPrefix":{"type":"string","description":"Pull Request Source Branch Prefix","ignoreCase":"key"},"azureReposGitPatVariable":{"type":"string","description":"Variable for Azure Repos Git PAT","ignoreCase":"key"},"gitHubPatVariable":{"type":"string","description":"Variable for GitHub PAT","ignoreCase":"key"},"isShouldReusePrSelected":{"type":"boolean","description":"Reuse an existing, active pull request if available","ignoreCase":"key"},"isAutoCompletePrSelected":{"type":"boolean","description":"Auto-Complete a pull request","ignoreCase":"key"},"isDeletePrSourceBranchSelected":{"type":"boolean","description":"Delete a source branch after completing a pull request","ignoreCase":"key"},"isUseLfLineEndingsSelected":{"type":"boolean","description":"Use LF line endings when localized files are checked-in","ignoreCase":"key"},"gitHubPrMergeMethod":{"description":"Pull Request Merge Method","ignoreCase":"all","enum":["merge","squash","rebase"]},"isMirrorRepoSelected":{"type":"boolean","description":"Check-in localized files to the mirror repo","ignoreCase":"key"},"gitHubOrganization":{"type":"string","description":"GitHub Organization","ignoreCase":"key"},"adoOrganization":{"type":"string","description":"Azure DevOps Organization URL","ignoreCase":"key"},"adoProject":{"type":"string","description":"Azure DevOps Project","ignoreCase":"key"},"mirrorRepo":{"type":"string","description":"Mirror Repo","ignoreCase":"key"},"mirrorBranch":{"type":"string","description":"Mirror Branch","ignoreCase":"key"},"packageSourceAuth":{"description":"Package Source Authentication","ignoreCase":"all","enum":["credentialProviderAuth","patAuth"]},"patVariable":{"type":"string","description":"Variable for Package PAT","ignoreCase":"key"},"lsBuildPackageId":{"description":"LSBuild Package ID","ignoreCase":"all","enum":["lsBuildXLoc","lsBuildLegacyXLoc"]},"lsBuildXLocPackageVersion":{"type":"string","description":"LSBuild.XLoc Package Version","ignoreCase":"key"},"lsBuildLegacyXLocPackageVersion":{"type":"string","description":"LSBuild.Legacy.XLoc Package Version","ignoreCase":"key"},"lsBuildWarningLevel":{"description":"LSBuild Warning Level","ignoreCase":"all","enum":["0","1","2","3","4"]},"xLocConsoleLoggingLevel":{"description":"XLoc Tool Console Logging Level","ignoreCase":"all","enum":["verbose","debug","information","warning","error","fatal"]},"nugetCliVersion":{"type":"string","description":"NuGet CLI Version","ignoreCase":"key"},"isOutputLocStatusSelected":{"type":"boolean","description":"Output the status of localization completeness","ignoreCase":"key"},"xLocCustomPowerShellScript":{"type":"string","description":"XLoc Tool Custom PowerShell Script","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Jenkins download artifacts\n\nDownload artifacts produced by a Jenkins job","ignoreCase":"value","pattern":"^JenkinsDownloadArtifacts@1$"},"inputs":{"description":"Jenkins download artifacts inputs","properties":{"jenkinsServerConnection":{"type":"string","description":"Jenkins service connection","ignoreCase":"key","aliases":["serverEndpoint"]},"jobName":{"type":"string","description":"Job name","ignoreCase":"key"},"jenkinsJobType":{"type":"string","description":"Jenkins job type","ignoreCase":"key"},"saveTo":{"type":"string","description":"Save to","ignoreCase":"key"},"jenkinsBuild":{"description":"Download artifacts produced by","ignoreCase":"all","enum":["LastSuccessfulBuild","BuildNumber"]},"jenkinsBuildNumber":{"type":"string","description":"Jenkins build number","ignoreCase":"key"},"itemPattern":{"type":"string","description":"Item Pattern","ignoreCase":"key"},"downloadCommitsAndWorkItems":{"type":"boolean","description":"Download Commits and WorkItems","ignoreCase":"key"},"startJenkinsBuildNumber":{"type":"string","description":"Download commits and work items from","ignoreCase":"key"},"artifactDetailsFileNameSuffix":{"type":"string","description":"Commit and WorkItem FileName","ignoreCase":"key"},"propagatedArtifacts":{"type":"boolean","description":"Artifacts are propagated to Azure","ignoreCase":"key"},"artifactProvider":{"description":"Artifact Provider","ignoreCase":"all","enum":["azureStorage"]},"ConnectedServiceNameARM":{"type":"string","description":"Azure Subscription","ignoreCase":"key"},"storageAccountName":{"type":"string","description":"Storage Account Name","ignoreCase":"key"},"containerName":{"type":"string","description":"Container Name","ignoreCase":"key"},"commonVirtualPath":{"type":"string","description":"Common Virtual Path","ignoreCase":"key"}},"additionalProperties":false,"required":["jenkinsServerConnection","jobName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure Functions for container\n\nUpdate a function app with a Docker container","ignoreCase":"value","pattern":"^AzureFunctionAppContainer@1$"},"inputs":{"description":"Azure Functions for container inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"appName":{"type":"string","description":"App name","ignoreCase":"key"},"deployToSlotOrASE":{"type":"boolean","description":"Deploy to Slot or App Service Environment","ignoreCase":"key"},"resourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"slotName":{"type":"string","description":"Slot","ignoreCase":"key"},"imageName":{"type":"string","description":"Image name","ignoreCase":"key"},"containerCommand":{"type":"string","description":"Startup command ","ignoreCase":"key"},"appSettings":{"type":"string","description":"App settings","ignoreCase":"key"},"configurationStrings":{"type":"string","description":"Configuration settings","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","appName","imageName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Decrypt file (OpenSSL)\n\nDecrypt a file using OpenSSL","ignoreCase":"value","pattern":"^DecryptFile@1$"},"inputs":{"description":"Decrypt file (OpenSSL) inputs","properties":{"cipher":{"type":"string","description":"Cypher","ignoreCase":"key"},"inFile":{"type":"string","description":"Encrypted file","ignoreCase":"key"},"passphrase":{"type":"string","description":"Passphrase","ignoreCase":"key"},"outFile":{"type":"string","description":"Decrypted file path","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]}},"additionalProperties":false,"required":["inFile","passphrase"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Package and deploy Helm charts\n\nDeploy, configure, update a Kubernetes cluster in Azure Container Service by running helm commands","ignoreCase":"value","pattern":"^HelmDeploy@0$"},"inputs":{"description":"Package and deploy Helm charts inputs","properties":{"connectionType":{"description":"Connection Type","ignoreCase":"all","enum":["Azure Resource Manager","Kubernetes Service Connection","None"]},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["azureSubscriptionEndpoint"]},"azureResourceGroup":{"type":"string","description":"Resource group","ignoreCase":"key"},"kubernetesCluster":{"type":"string","description":"Kubernetes cluster","ignoreCase":"key"},"useClusterAdmin":{"type":"boolean","description":"Use cluster admin credentials","ignoreCase":"key"},"kubernetesServiceConnection":{"type":"string","description":"Kubernetes Service Connection","ignoreCase":"key","aliases":["kubernetesServiceEndpoint"]},"namespace":{"type":"string","description":"Namespace","ignoreCase":"key"},"azureSubscriptionForACR":{"type":"string","description":"Azure subscription for Container Registry","ignoreCase":"key","aliases":["azureSubscriptionEndpointForACR"]},"azureResourceGroupForACR":{"type":"string","description":"Resource group","ignoreCase":"key"},"azureContainerRegistry":{"type":"string","description":"Azure Container Registry","ignoreCase":"key"},"command":{"description":"Command","ignoreCase":"all","enum":["create","delete","expose","get","init","install","login","logout","ls","package","rollback","save","upgrade","uninstall"]},"chartType":{"description":"Chart Type","ignoreCase":"all","enum":["Name","FilePath"]},"chartName":{"type":"string","description":"Chart Name","ignoreCase":"key"},"chartPath":{"type":"string","description":"Chart Path","ignoreCase":"key"},"chartVersion":{"type":"string","description":"Version","ignoreCase":"key","aliases":["version"]},"releaseName":{"type":"string","description":"Release Name","ignoreCase":"key"},"overrideValues":{"type":"string","description":"Set Values","ignoreCase":"key"},"valueFile":{"type":"string","description":"Value File","ignoreCase":"key"},"destination":{"type":"string","description":"Destination","ignoreCase":"key"},"canaryImage":{"type":"boolean","description":"Use canary image version.","ignoreCase":"key","aliases":["canaryimage"]},"upgradeTiller":{"type":"boolean","description":"Upgrade Tiller","ignoreCase":"key","aliases":["upgradetiller"]},"updateDependency":{"type":"boolean","description":"Update Dependency","ignoreCase":"key","aliases":["updatedependency"]},"save":{"type":"boolean","description":"Save","ignoreCase":"key"},"install":{"type":"boolean","description":"Install if release not present.","ignoreCase":"key"},"recreate":{"type":"boolean","description":"Recreate Pods.","ignoreCase":"key"},"resetValues":{"type":"boolean","description":"Reset Values.","ignoreCase":"key"},"force":{"type":"boolean","description":"Force","ignoreCase":"key"},"waitForExecution":{"type":"boolean","description":"Wait","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"enableTls":{"type":"boolean","description":"Enable TLS","ignoreCase":"key"},"caCert":{"type":"string","description":"CA certificate","ignoreCase":"key"},"certificate":{"type":"string","description":"Certificate","ignoreCase":"key"},"privatekey":{"type":"string","description":"Key","ignoreCase":"key"},"tillerNamespace":{"type":"string","description":"Tiller namespace","ignoreCase":"key","aliases":["tillernamespace"]},"failOnStderr":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"},"publishPipelineMetadata":{"type":"boolean","description":"Publish pipeline metadata","ignoreCase":"key"},"chartNameForACR":{"type":"string","description":"Chart Name For Azure Container Registry","ignoreCase":"key"},"chartPathForACR":{"type":"string","description":"Chart Path for Azure Container Registry","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscriptionForACR","azureResourceGroupForACR","azureContainerRegistry"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Install Apple certificate\n\nInstall an Apple certificate required to build on a macOS agent machine","ignoreCase":"value","pattern":"^InstallAppleCertificate@2$"},"inputs":{"description":"Install Apple certificate inputs","properties":{"certSecureFile":{"type":"string","description":"Certificate (P12)","ignoreCase":"key"},"certPwd":{"type":"string","description":"Certificate (P12) password","ignoreCase":"key"},"keychain":{"description":"Keychain","ignoreCase":"all","enum":["default","temp","custom"]},"keychainPassword":{"type":"string","description":"Keychain password","ignoreCase":"key"},"customKeychainPath":{"type":"string","description":"Custom keychain path","ignoreCase":"key"},"deleteCert":{"type":"boolean","description":"Delete certificate from keychain","ignoreCase":"key"},"deleteCustomKeychain":{"type":"boolean","description":"Delete custom keychain","ignoreCase":"key"},"signingIdentity":{"type":"string","description":"Certificate signing identity","ignoreCase":"key"},"setUpPartitionIdACLForPrivateKey":{"type":"boolean","description":"Set up partition_id ACL for the imported private key","ignoreCase":"key"}},"additionalProperties":false,"required":["certSecureFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Install Apple Certificate\n\nInstall an Apple certificate required to build on a macOS agent","ignoreCase":"value","pattern":"^InstallAppleCertificate@1$"},"inputs":{"description":"Install Apple Certificate inputs","properties":{"certSecureFile":{"type":"string","description":"Certificate (P12)","ignoreCase":"key"},"certPwd":{"type":"string","description":"Certificate (P12) password","ignoreCase":"key"},"keychain":{"description":"Keychain","ignoreCase":"all","enum":["default","temp","custom"]},"keychainPassword":{"type":"string","description":"Keychain password","ignoreCase":"key"},"customKeychainPath":{"type":"string","description":"Custom keychain path","ignoreCase":"key"},"deleteCert":{"type":"boolean","description":"Delete certificate from keychain","ignoreCase":"key"},"deleteCustomKeychain":{"type":"boolean","description":"Delete custom keychain","ignoreCase":"key"},"signingIdentity":{"type":"string","description":"Certificate signing identity","ignoreCase":"key"}},"additionalProperties":false,"required":["certSecureFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Install Apple Certificate\n\nInstall an Apple certificate required to build on a macOS agent","ignoreCase":"value","pattern":"^InstallAppleCertificate@0$"},"inputs":{"description":"Install Apple Certificate inputs","properties":{"certSecureFile":{"type":"string","description":"Certificate (P12)","ignoreCase":"key"},"certPwd":{"type":"string","description":"Certificate (P12) Password","ignoreCase":"key"},"keychain":{"description":"Keychain","ignoreCase":"all","enum":["default","temp","custom"]},"keychainPassword":{"type":"string","description":"Keychain Password","ignoreCase":"key"},"customKeychainPath":{"type":"string","description":"Custom Keychain Path","ignoreCase":"key"},"deleteCert":{"type":"boolean","description":"Delete Certificate from Keychain","ignoreCase":"key"},"deleteCustomKeychain":{"type":"boolean","description":"Delete Custom Keychain","ignoreCase":"key"},"signingIdentity":{"type":"string","description":"Certificate Signing Identity","ignoreCase":"key"}},"additionalProperties":false,"required":["certSecureFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"ESRP Code Signing\n\nMicrosoft Internal tool for Code Signing files using ESRP Service","ignoreCase":"value","pattern":"^EsrpCodeSigning@1$"},"inputs":{"description":"ESRP Code Signing inputs","properties":{"ConnectedServiceName":{"type":"string","description":"Connection Name","ignoreCase":"key"},"FolderPath":{"type":"string","description":"Root folder path to get input files for signing","ignoreCase":"key"},"signType":{"description":"Sign Categories","ignoreCase":"all","enum":["regularSigning","batchSigning"]},"Pattern":{"type":"string","description":"File search pattern to discover to be signed files inside RootFolder variable","ignoreCase":"key"},"UseMinimatch":{"type":"boolean","description":"Use Minimatch","ignoreCase":"key"},"batchSignPolicyFile":{"type":"string","description":"BatchSign Policy File Input","ignoreCase":"key"},"ciPolicyFile":{"type":"string","description":"CI Policy File Input","ignoreCase":"key"},"guardianToolTimeout":{"type":"string","description":"Max Guardian Tool Run Time (minutes)","ignoreCase":"key"},"signConfigType":{"description":"Signing Configurations","ignoreCase":"all","enum":["legacyCops","inlineSignParams"]},"CertificateId":{"type":"string","description":"Certificate Id","ignoreCase":"key"},"OpusName":{"type":"string","description":"Product Name","ignoreCase":"key"},"OpusInfo":{"type":"string","description":"Product info url","ignoreCase":"key"},"inlineOperation":{"type":"string","description":"Inline Signing Configurations","ignoreCase":"key"},"SessionTimeout":{"type":"string","description":"Max Session Time (minutes)","ignoreCase":"key"},"ServiceEndpointUrl":{"type":"string","description":"API Endpoint Url","ignoreCase":"key"},"MaxConcurrency":{"type":"string","description":"Max Concurrency","ignoreCase":"key"},"MaxRetryAttempts":{"type":"string","description":"Max Retry Attempts","ignoreCase":"key"},"CleanupTempStorage":{"type":"boolean","description":"Cleanup all temp blob storage","ignoreCase":"key"},"VerboseLogin":{"type":"boolean","description":"Verbose Logs","ignoreCase":"key"},"tlsVersion":{"description":"TLS Version","ignoreCase":"all","enum":["Tls","Tls11","Tls12"]}},"additionalProperties":false,"required":["ConnectedServiceName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Invoke Azure Function\n\nInvoke an Azure Function","ignoreCase":"value","pattern":"^AzureFunction@1$"},"inputs":{"description":"Invoke Azure Function inputs","properties":{"function":{"type":"string","description":"Azure function URL","ignoreCase":"key"},"key":{"type":"string","description":"Function key","ignoreCase":"key"},"method":{"description":"Method","ignoreCase":"all","enum":["OPTIONS","GET","HEAD","POST","PUT","DELETE","TRACE","PATCH"]},"headers":{"type":"string","description":"Headers","ignoreCase":"key"},"queryParameters":{"type":"string","description":"Query parameters","ignoreCase":"key"},"body":{"type":"string","description":"Body","ignoreCase":"key"},"waitForCompletion":{"description":"Completion event","ignoreCase":"all","enum":["true","false"]},"successCriteria":{"type":"string","description":"Success criteria","ignoreCase":"key"}},"additionalProperties":false,"required":["function","key"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Invoke Azure Function\n\nInvoke Azure function as a part of your process.","ignoreCase":"value","pattern":"^AzureFunction@0$"},"inputs":{"description":"Invoke Azure Function inputs","properties":{"function":{"type":"string","description":"Azure function url","ignoreCase":"key"},"key":{"type":"string","description":"Function key","ignoreCase":"key"},"method":{"description":"Method","ignoreCase":"all","enum":["OPTIONS","GET","HEAD","POST","PUT","DELETE","TRACE","PATCH"]},"headers":{"type":"string","description":"Headers","ignoreCase":"key"},"queryParameters":{"type":"string","description":"Query parameters","ignoreCase":"key"},"body":{"type":"string","description":"Body","ignoreCase":"key"},"waitForCompletion":{"description":"Complete based on","ignoreCase":"all","enum":["true","false"]},"successCriteria":{"type":"string","description":"Success criteria","ignoreCase":"key"}},"additionalProperties":false,"required":["function","key"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Nuget Security Analysis\n\nA task to scan for vulnerabilities in nuget files.","ignoreCase":"value","pattern":"^nuget-security-analysis@0$"},"inputs":{"description":"Nuget Security Analysis inputs","properties":{},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"DacPac Schema Compare\n\nProvides a report on database model changes since the last build","ignoreCase":"value","pattern":"^DacPacReport@1$"},"inputs":{"description":"DacPac Schema Compare inputs","properties":{"dropName":{"type":"string","description":"Drop Name","ignoreCase":"key"},"dacpacName":{"type":"string","description":"DacPac Name","ignoreCase":"key"},"targetDacPacPath":{"type":"string","description":"Compiled DacPac Path","ignoreCase":"key"},"extraArgs":{"type":"string","description":"Extra SQLPackage args","ignoreCase":"key"},"reverse":{"type":"boolean","description":"Reverse Comparison","ignoreCase":"key"},"userSqlPackagePath":{"type":"string","description":"SQL Package exe filepath","ignoreCase":"key"}},"additionalProperties":false,"required":["dacpacName","targetDacPacPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Download GitHub Release\n\nDownloads a GitHub Release from a repository","ignoreCase":"value","pattern":"^DownloadGitHubRelease@0$"},"inputs":{"description":"Download GitHub Release inputs","properties":{"connection":{"type":"string","description":"GitHub Connection","ignoreCase":"key"},"userRepository":{"type":"string","description":"Repository","ignoreCase":"key"},"defaultVersionType":{"description":"Default version","ignoreCase":"all","enum":["latest","specificVersion","specificTag"]},"version":{"type":"string","description":"Release","ignoreCase":"key"},"itemPattern":{"type":"string","description":"Item Pattern","ignoreCase":"key"},"downloadPath":{"type":"string","description":"Destination directory","ignoreCase":"key"}},"additionalProperties":false,"required":["connection","userRepository"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"SSH\n\nRun shell commands or a script on a remote machine using SSH","ignoreCase":"value","pattern":"^SSH@0$"},"inputs":{"description":"SSH inputs","properties":{"sshEndpoint":{"type":"string","description":"SSH service connection","ignoreCase":"key"},"runOptions":{"description":"Run","ignoreCase":"all","enum":["commands","script","inline"]},"commands":{"type":"string","description":"Commands","ignoreCase":"key"},"scriptPath":{"type":"string","description":"Shell script path","ignoreCase":"key"},"inline":{"type":"string","description":"Inline Script","ignoreCase":"key"},"interpreterCommand":{"type":"string","description":"Interpreter command","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"failOnStdErr":{"type":"boolean","description":"Fail on STDERR","ignoreCase":"key"},"interactiveSession":{"type":"boolean","description":"Enable interactive session","ignoreCase":"key"},"readyTimeout":{"type":"string","description":"SSH handshake timeout","ignoreCase":"key"}},"additionalProperties":false,"required":["sshEndpoint"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Publish Pipeline Artifacts\n\nPublish (upload) a file or directory as a named artifact for the current run","ignoreCase":"value","pattern":"^PublishPipelineArtifact@1$"},"inputs":{"description":"Publish Pipeline Artifacts inputs","properties":{"targetPath":{"type":"string","description":"File or directory path","ignoreCase":"key","aliases":["path"]},"artifact":{"type":"string","description":"Artifact name","ignoreCase":"key","aliases":["artifactName"]},"publishLocation":{"description":"Artifact publish location","ignoreCase":"all","enum":["pipeline","filepath"],"aliases":["artifactType"]},"fileSharePath":{"type":"string","description":"File share path","ignoreCase":"key"},"parallel":{"type":"boolean","description":"Parallel copy","ignoreCase":"key"},"parallelCount":{"type":"integer","description":"Parallel count","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Publish pipeline artifact\n\nPublish a local directory or file as a named artifact for the current pipeline","ignoreCase":"value","pattern":"^PublishPipelineArtifact@0$"},"inputs":{"description":"Publish pipeline artifact inputs","properties":{"artifactName":{"type":"string","description":"The name of this artifact","ignoreCase":"key"},"targetPath":{"type":"string","description":"Path to publish","ignoreCase":"key"}},"additionalProperties":false,"required":["targetPath"]}},"deprecationMessage":"PublishPipelineArtifact is deprecated - Publish a local directory or file as a named artifact for the current pipeline","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"SonarQube for MSBuild - Begin Analysis\n\n[DEPRECATED] Fetch the Quality Profile from SonarQube to configure the analysis","ignoreCase":"value","pattern":"^SonarQubePreBuild@1$"},"inputs":{"description":"SonarQube for MSBuild - Begin Analysis inputs","properties":{"projectKey":{"type":"string","description":"Project Key","ignoreCase":"key"},"projectName":{"type":"string","description":"Project Name","ignoreCase":"key"},"projectVersion":{"type":"string","description":"Project Version","ignoreCase":"key"},"connectedServiceName":{"type":"string","description":"SonarQube Endpoint","ignoreCase":"key"},"dbUrl":{"type":"string","description":"Db Connection String","ignoreCase":"key"},"dbUsername":{"type":"string","description":"Db UserName","ignoreCase":"key"},"dbPassword":{"type":"string","description":"Db User Password","ignoreCase":"key"},"cmdLineArgs":{"type":"string","description":"Additional Settings","ignoreCase":"key"},"configFile":{"type":"string","description":"Settings File","ignoreCase":"key"},"includeFullReport":{"type":"boolean","description":"Include full analysis report in the build summary (SQ 5.3+)","ignoreCase":"key"},"breakBuild":{"type":"boolean","description":"Fail the build on quality gate failure (SQ 5.3+)","ignoreCase":"key"}},"additionalProperties":false,"required":["projectKey","projectName","connectedServiceName"]}},"deprecationMessage":"SonarQubePreBuild is deprecated - [DEPRECATED] Fetch the Quality Profile from SonarQube to configure the analysis","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Build VS Bootstrapper\n\nBuilds a VS Bootstrapper including the changes of the manifests from one or more components","ignoreCase":"value","pattern":"^MicroBuildBuildVSBootstrapper@2$"},"inputs":{"description":"MicroBuild Build VS Bootstrapper inputs","properties":{"channelName":{"type":"string","description":"VS Channel","ignoreCase":"key"},"vsMajorVersion":{"type":"string","description":"VS Major Version","ignoreCase":"key"},"manifests":{"type":"string","description":"Overlay Manifests","ignoreCase":"key"},"outputFolder":{"type":"string","description":"Bootstrapper Folder","ignoreCase":"key"},"buildBranch":{"type":"string","description":"VS Branch","ignoreCase":"key"},"buildNumber":{"type":"string","description":"VS Build Number","ignoreCase":"key"},"bootstrapperCoreVersion":{"type":"string","description":"Bootstrapper Core Version","ignoreCase":"key"},"bootstrapperCoreFeedSource":{"type":"string","description":"Bootstrapper NuGet Feed","ignoreCase":"key"},"bootstrapperCoreDependenciesFeedSource":{"type":"string","description":"Bootstrapper Dependencies NuGet Feed","ignoreCase":"key"},"nugetOrgPublicFeedSource":{"type":"string","description":"NuGet.org feed location","ignoreCase":"key"}},"additionalProperties":false,"required":["manifests","outputFolder"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Build VS Bootstrapper\n\nBuilds a VS Bootstrapper including the changes of the manifests from one or more components","ignoreCase":"value","pattern":"^MicroBuildBuildVSBootstrapper@1$"},"inputs":{"description":"MicroBuild Build VS Bootstrapper inputs","properties":{"channelName":{"type":"string","description":"VS Channel","ignoreCase":"key"},"vsMajorVersion":{"type":"string","description":"VS Major Version","ignoreCase":"key"},"manifests":{"type":"string","description":"Overlay Manifests","ignoreCase":"key"},"outputFolder":{"type":"string","description":"Bootstrapper Folder","ignoreCase":"key"},"buildBranch":{"type":"string","description":"VS Branch","ignoreCase":"key"},"buildNumber":{"type":"string","description":"VS Build Number","ignoreCase":"key"},"bootstrapperCoreVersion":{"type":"string","description":"Bootstrapper Core Version","ignoreCase":"key"},"bootstrapperCoreFeedSource":{"type":"string","description":"Bootstrapper NuGet Feed","ignoreCase":"key"},"bootstrapperCoreDependenciesFeedSource":{"type":"string","description":"Bootstrapper Dependencies NuGet Feed","ignoreCase":"key"},"nugetOrgPublicFeedSource":{"type":"string","description":"NuGet.org feed location","ignoreCase":"key"}},"additionalProperties":false,"required":["manifests","outputFolder"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Download artifacts from file share\n\nDownload artifacts from a file share, like \\\\share\\drop","ignoreCase":"value","pattern":"^DownloadFileshareArtifacts@1$"},"inputs":{"description":"Download artifacts from file share inputs","properties":{"filesharePath":{"type":"string","description":"File share path","ignoreCase":"key"},"artifactName":{"type":"string","description":"Artifact name","ignoreCase":"key"},"itemPattern":{"type":"string","description":"Matching pattern","ignoreCase":"key"},"downloadPath":{"type":"string","description":"Download path","ignoreCase":"key"},"parallelizationLimit":{"type":"string","description":"Parallelization limit","ignoreCase":"key"}},"additionalProperties":false,"required":["filesharePath","artifactName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Kubectl\n\nDeploy, configure, update a Kubernetes cluster in Azure Container Service by running kubectl commands","ignoreCase":"value","pattern":"^Kubernetes@1$"},"inputs":{"description":"Kubectl inputs","properties":{"connectionType":{"description":"Service connection type","ignoreCase":"all","enum":["Azure Resource Manager","Kubernetes Service Connection","None"]},"kubernetesServiceEndpoint":{"type":"string","description":"Kubernetes service connection","ignoreCase":"key"},"azureSubscriptionEndpoint":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"azureResourceGroup":{"type":"string","description":"Resource group","ignoreCase":"key"},"kubernetesCluster":{"type":"string","description":"Kubernetes cluster","ignoreCase":"key"},"useClusterAdmin":{"type":"boolean","description":"Use cluster admin credentials","ignoreCase":"key"},"namespace":{"type":"string","description":"Namespace","ignoreCase":"key"},"command":{"description":"Command","ignoreCase":"all","enum":["apply","create","delete","exec","expose","get","login","logout","logs","run","set","top"]},"useConfigurationFile":{"type":"boolean","description":"Use configuration","ignoreCase":"key"},"configurationType":{"description":"Configuration type","ignoreCase":"all","enum":["configuration","inline"]},"configuration":{"type":"string","description":"File path","ignoreCase":"key"},"inline":{"type":"string","description":"Inline configuration","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"secretType":{"description":"Type of secret","ignoreCase":"all","enum":["dockerRegistry","generic"]},"secretArguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"containerRegistryType":{"description":"Container registry type","ignoreCase":"all","enum":["Azure Container Registry","Container Registry"]},"dockerRegistryEndpoint":{"type":"string","description":"Docker registry service connection","ignoreCase":"key"},"azureSubscriptionEndpointForSecrets":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"azureContainerRegistry":{"type":"string","description":"Azure container registry","ignoreCase":"key"},"secretName":{"type":"string","description":"Secret name","ignoreCase":"key"},"forceUpdate":{"type":"boolean","description":"Force update secret","ignoreCase":"key"},"configMapName":{"type":"string","description":"ConfigMap name","ignoreCase":"key"},"forceUpdateConfigMap":{"type":"boolean","description":"Force update configmap","ignoreCase":"key"},"useConfigMapFile":{"type":"boolean","description":"Use file","ignoreCase":"key"},"configMapFile":{"type":"string","description":"ConfigMap file","ignoreCase":"key"},"configMapArguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"versionOrLocation":{"description":"Kubectl","ignoreCase":"all","enum":["version","location"]},"versionSpec":{"type":"string","description":"Version spec","ignoreCase":"key"},"checkLatest":{"type":"boolean","description":"Check for latest version","ignoreCase":"key"},"specifyLocation":{"type":"string","description":"Path to kubectl","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]},"outputFormat":{"description":"Output format","ignoreCase":"all","enum":["json","yaml","none"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Kubectl\n\nDeploy, configure, update a Kubernetes cluster in Azure Container Service by running kubectl commands","ignoreCase":"value","pattern":"^Kubernetes@0$"},"inputs":{"description":"Kubectl inputs","properties":{"kubernetesServiceConnection":{"type":"string","description":"Kubernetes service connection","ignoreCase":"key","aliases":["kubernetesServiceEndpoint"]},"namespace":{"type":"string","description":"Namespace","ignoreCase":"key"},"command":{"description":"Command","ignoreCase":"all","enum":["apply","create","delete","exec","expose","get","logs","run","set","top"]},"useConfigurationFile":{"type":"boolean","description":"Use Configuration files","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration file","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"secretType":{"description":"Type of secret","ignoreCase":"all","enum":["dockerRegistry","generic"]},"secretArguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"containerRegistryType":{"description":"Container Registry type","ignoreCase":"all","enum":["Azure Container Registry","Container Registry"]},"dockerRegistryConnection":{"type":"string","description":"Docker Registry service connection","ignoreCase":"key","aliases":["dockerRegistryEndpoint"]},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["azureSubscriptionEndpoint"]},"azureContainerRegistry":{"type":"string","description":"Azure Container Registry","ignoreCase":"key"},"secretName":{"type":"string","description":"Secret name","ignoreCase":"key"},"forceUpdate":{"type":"boolean","description":"Force update secret","ignoreCase":"key"},"configMapName":{"type":"string","description":"ConfigMap name","ignoreCase":"key"},"forceUpdateConfigMap":{"type":"boolean","description":"Force update configmap","ignoreCase":"key"},"useConfigMapFile":{"type":"boolean","description":"Use file","ignoreCase":"key"},"configMapFile":{"type":"string","description":"ConfigMap file","ignoreCase":"key"},"configMapArguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"versionOrLocation":{"description":"Kubectl","ignoreCase":"all","enum":["version","location"]},"versionSpec":{"type":"string","description":"Version spec","ignoreCase":"key"},"checkLatest":{"type":"boolean","description":"Check for latest version","ignoreCase":"key"},"specifyLocation":{"type":"string","description":"Path to Kubectl","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]},"outputFormat":{"description":"Output format","ignoreCase":"all","enum":["json","yaml"]},"kubectlOutput":{"type":"string","description":"Output variable name","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure IoT Edge\n\nBuild and deploy an Azure IoT Edge image","ignoreCase":"value","pattern":"^AzureIoTEdge@2$"},"inputs":{"description":"Azure IoT Edge inputs","properties":{"action":{"description":"Action","ignoreCase":"all","enum":["Build module images","Push module images","Generate deployment manifest","Deploy to IoT Edge devices"]},"deploymentFilePath":{"type":"string","description":"Deployment file","ignoreCase":"key"},"azureSubscription":{"type":"string","description":"Azure subscription contains IoT Hub","ignoreCase":"key","aliases":["connectedServiceNameARM"]},"iothubname":{"type":"string","description":"IoT Hub name","ignoreCase":"key"},"deploymentid":{"type":"string","description":"IoT Edge deployment ID","ignoreCase":"key"},"priority":{"type":"string","description":"IoT Edge deployment priority","ignoreCase":"key"},"deviceOption":{"description":"Choose single/multiple device","ignoreCase":"all","enum":["Single Device","Multiple Devices"]},"deviceId":{"type":"string","description":"IoT Edge device ID","ignoreCase":"key"},"targetcondition":{"type":"string","description":"IoT Edge device target condition","ignoreCase":"key"},"containerregistrytype":{"description":"Container registry type","ignoreCase":"all","enum":["Azure Container Registry","Generic Container Registry"]},"dockerRegistryConnection":{"type":"string","description":"Docker Registry Connection","ignoreCase":"key","aliases":["dockerRegistryEndpoint"]},"azureSubscriptionEndpoint":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"azureContainerRegistry":{"type":"string","description":"Azure Container Registry","ignoreCase":"key"},"templateFilePath":{"type":"string","description":".template.json file","ignoreCase":"key"},"defaultPlatform":{"description":"Default platform","ignoreCase":"all","enum":["amd64","windows-amd64","arm32v7","arm64v8"]},"fillRegistryCredential":{"description":"Add registry credential to deployment manifest","ignoreCase":"all","enum":["true","false"]},"deploymentManifestOutputPath":{"type":"string","description":"Output path","ignoreCase":"key"},"validateGeneratedDeploymentManifest":{"description":"Validate the schema of generated deployment manifest","ignoreCase":"all","enum":["true","false"]},"bypassModules":{"type":"string","description":"Bypass module(s)","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Service Fabric Compose deploy\n\nDeploy a Docker Compose application to an Azure Service Fabric cluster","ignoreCase":"value","pattern":"^ServiceFabricComposeDeploy@0$"},"inputs":{"description":"Service Fabric Compose deploy inputs","properties":{"clusterConnection":{"type":"string","description":"Cluster Service Connection","ignoreCase":"key","aliases":["serviceConnectionName"]},"composeFilePath":{"type":"string","description":"Compose File Path","ignoreCase":"key"},"applicationName":{"type":"string","description":"Application Name","ignoreCase":"key"},"registryCredentials":{"description":"Registry Credentials Source","ignoreCase":"all","enum":["AzureResourceManagerEndpoint","ContainerRegistryEndpoint","UsernamePassword","None"]},"dockerRegistryConnection":{"type":"string","description":"Docker Registry Service Connection","ignoreCase":"key","aliases":["dockerRegistryEndpointName"]},"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["azureSubscriptionEndpoint"]},"registryUserName":{"type":"string","description":"Registry User Name","ignoreCase":"key"},"registryPassword":{"type":"string","description":"Registry Password","ignoreCase":"key"},"passwordEncrypted":{"type":"boolean","description":"Password Encrypted","ignoreCase":"key"},"upgrade":{"type":"boolean","description":"Upgrade","ignoreCase":"key"},"deployTimeoutSec":{"type":"string","description":"Deploy Timeout (s)","ignoreCase":"key"},"removeTimeoutSec":{"type":"string","description":"Remove Timeout (s)","ignoreCase":"key"},"getStatusTimeoutSec":{"type":"string","description":"Get Status Timeout (s)","ignoreCase":"key"}},"additionalProperties":false,"required":["clusterConnection"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Android signing\n\nSign and align Android APK files","ignoreCase":"value","pattern":"^AndroidSigning@2$"},"inputs":{"description":"Android signing inputs","properties":{"apkFiles":{"type":"string","description":"APK files","ignoreCase":"key","aliases":["files"]},"jarsign":{"type":"boolean","description":"Sign the APK","ignoreCase":"key"},"jarsignerKeystoreFile":{"type":"string","description":"Keystore file","ignoreCase":"key","aliases":["keystoreFile"]},"jarsignerKeystorePassword":{"type":"string","description":"Keystore password","ignoreCase":"key","aliases":["keystorePass"]},"jarsignerKeystoreAlias":{"type":"string","description":"Alias","ignoreCase":"key","aliases":["keystoreAlias"]},"jarsignerKeyPassword":{"type":"string","description":"Key password","ignoreCase":"key","aliases":["keyPass"]},"jarsignerArguments":{"type":"string","description":"Jarsigner arguments","ignoreCase":"key"},"zipalign":{"type":"boolean","description":"Zipalign","ignoreCase":"key"},"zipalignFile":{"type":"string","description":"Zipalign location","ignoreCase":"key","aliases":["zipalignLocation"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Android Signing\n\nSign and align Android APK files","ignoreCase":"value","pattern":"^AndroidSigning@1$"},"inputs":{"description":"Android Signing inputs","properties":{"files":{"type":"string","description":"APK Files","ignoreCase":"key"},"jarsign":{"type":"boolean","description":"Sign the APK","ignoreCase":"key"},"keystoreFile":{"type":"string","description":"Keystore File","ignoreCase":"key"},"keystorePass":{"type":"string","description":"Keystore Password","ignoreCase":"key"},"keystoreAlias":{"type":"string","description":"Alias","ignoreCase":"key"},"keyPass":{"type":"string","description":"Key Password","ignoreCase":"key"},"jarsignerArguments":{"type":"string","description":"Jarsigner Arguments","ignoreCase":"key"},"zipalign":{"type":"boolean","description":"Zipalign","ignoreCase":"key"},"zipalignLocation":{"type":"string","description":"Zipalign Location","ignoreCase":"key"}},"additionalProperties":false,"required":["files"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Android signing\n\nSign and align Android APK files","ignoreCase":"value","pattern":"^AndroidSigning@3$"},"inputs":{"description":"Android signing inputs","properties":{"apkFiles":{"type":"string","description":"APK files","ignoreCase":"key","aliases":["files"]},"apksign":{"type":"boolean","description":"Sign the APK","ignoreCase":"key"},"apksignerKeystoreFile":{"type":"string","description":"Keystore file","ignoreCase":"key","aliases":["keystoreFile"]},"apksignerKeystorePassword":{"type":"string","description":"Keystore password","ignoreCase":"key","aliases":["keystorePass"]},"apksignerKeystoreAlias":{"type":"string","description":"Alias","ignoreCase":"key","aliases":["keystoreAlias"]},"apksignerKeyPassword":{"type":"string","description":"Key password","ignoreCase":"key","aliases":["keyPass"]},"apksignerVersion":{"type":"string","description":"apksigner version","ignoreCase":"key"},"apksignerArguments":{"type":"string","description":"apksigner arguments","ignoreCase":"key"},"apksignerFile":{"type":"string","description":"apksigner location","ignoreCase":"key","aliases":["apksignerLocation"]},"zipalign":{"type":"boolean","description":"Zipalign","ignoreCase":"key"},"zipalignVersion":{"type":"string","description":"Zipalign version","ignoreCase":"key"},"zipalignFile":{"type":"string","description":"Zipalign location","ignoreCase":"key","aliases":["zipalignLocation"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Download pipeline artifact\n\nDownload a named artifact from a pipeline to a local path","ignoreCase":"value","pattern":"^DownloadPipelineArtifact@1$"},"inputs":{"description":"Download pipeline artifact inputs","properties":{"buildType":{"description":"Download artifacts produced by","ignoreCase":"all","enum":["current","specific"]},"project":{"type":"string","description":"Project","ignoreCase":"key"},"pipeline":{"type":"string","description":"Build pipeline","ignoreCase":"key","aliases":["definition"]},"specificBuildWithTriggering":{"type":"boolean","description":"When appropriate, download artifacts from the triggering build.","ignoreCase":"key"},"buildVersionToDownload":{"description":"Build version to download","ignoreCase":"all","enum":["latest","latestFromBranch","specific"]},"branchName":{"type":"string","description":"Branch name","ignoreCase":"key"},"pipelineId":{"type":"string","description":"Build","ignoreCase":"key","aliases":["buildId"]},"tags":{"type":"string","description":"Build Tags","ignoreCase":"key"},"artifactName":{"type":"string","description":"Artifact name","ignoreCase":"key"},"itemPattern":{"type":"string","description":"Matching pattern","ignoreCase":"key"},"targetPath":{"type":"string","description":"Destination directory","ignoreCase":"key","aliases":["downloadPath"]}},"additionalProperties":false,"required":[]}},"deprecationMessage":"DownloadPipelineArtifact is deprecated - Download a named artifact from a pipeline to a local path","doNotSuggest":true,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Download pipeline artifact\n\nDownloads an artifact associated with a pipeline","ignoreCase":"value","pattern":"^DownloadPipelineArtifact@0$"},"inputs":{"description":"Download pipeline artifact inputs","properties":{"pipelineId":{"type":"string","description":"The specific pipeline to download from","ignoreCase":"key"},"artifactName":{"type":"string","description":"The name of artifact to download.","ignoreCase":"key"},"targetPath":{"type":"string","description":"Path to download to","ignoreCase":"key"}},"additionalProperties":false,"required":["targetPath"]}},"deprecationMessage":"DownloadPipelineArtifact is deprecated - Downloads an artifact associated with a pipeline","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Download Pipeline Artifacts\n\nDownload build and pipeline artifacts","ignoreCase":"value","pattern":"^DownloadPipelineArtifact@2$"},"inputs":{"description":"Download Pipeline Artifacts inputs","properties":{"buildType":{"description":"Download artifacts produced by","ignoreCase":"all","enum":["current","specific"],"aliases":["source"]},"project":{"type":"string","description":"Project","ignoreCase":"key"},"definition":{"type":"string","description":"Build pipeline","ignoreCase":"key","aliases":["pipeline"]},"specificBuildWithTriggering":{"type":"boolean","description":"When appropriate, download artifacts from the triggering build.","ignoreCase":"key","aliases":["preferTriggeringPipeline"]},"buildVersionToDownload":{"description":"Build version to download","ignoreCase":"all","enum":["latest","latestFromBranch","specific"],"aliases":["runVersion"]},"branchName":{"type":"string","description":"Branch name","ignoreCase":"key","aliases":["runBranch"]},"pipelineId":{"type":"string","description":"Build","ignoreCase":"key","aliases":["runId","buildId"]},"tags":{"type":"string","description":"Build Tags","ignoreCase":"key"},"allowPartiallySucceededBuilds":{"type":"boolean","description":"Download artifacts from partially succeeded builds.","ignoreCase":"key"},"allowFailedBuilds":{"type":"boolean","description":"Download artifacts from failed builds.","ignoreCase":"key"},"artifactName":{"type":"string","description":"Artifact name","ignoreCase":"key","aliases":["artifact"]},"itemPattern":{"type":"string","description":"Matching patterns","ignoreCase":"key","aliases":["patterns"]},"targetPath":{"type":"string","description":"Destination directory","ignoreCase":"key","aliases":["path","downloadPath"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Use Python version\n\nUse the specified version of Python from the tool cache, optionally adding it to the PATH","ignoreCase":"value","pattern":"^UsePythonVersion@0$"},"inputs":{"description":"Use Python version inputs","properties":{"versionSpec":{"type":"string","description":"Version spec","ignoreCase":"key"},"addToPath":{"type":"boolean","description":"Add to PATH","ignoreCase":"key"},"architecture":{"description":"Architecture","ignoreCase":"all","enum":["x86","x64"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Accessibility Insights Azure DevOps Task\n\nScan accessibility issues in an Azure DevOps pipeline","ignoreCase":"value","pattern":"^accessibility-insights@1$"},"inputs":{"description":"Accessibility Insights Azure DevOps Task inputs","properties":{"repoServiceConnectionName":{"type":"string","description":"Azure Repos Connection","ignoreCase":"key"},"outputDir":{"type":"string","description":"Output Directory","ignoreCase":"key"},"siteDir":{"type":"string","description":"Site Directory","ignoreCase":"key"},"scanUrlRelativePath":{"type":"string","description":"Scan URL Relative Path","ignoreCase":"key"},"chromePath":{"type":"string","description":"Chrome Path","ignoreCase":"key"},"url":{"type":"string","description":"Website URL","ignoreCase":"key"},"maxUrls":{"type":"integer","description":"Maximum number of URLs","ignoreCase":"key"},"discoveryPatterns":{"type":"string","description":"Discovery Patterns","ignoreCase":"key"},"inputFile":{"type":"string","description":"Input File","ignoreCase":"key"},"inputUrls":{"type":"string","description":"Input URLs","ignoreCase":"key"},"localhostPort":{"type":"integer","description":"Localhost Port","ignoreCase":"key"},"scanTimeout":{"type":"integer","description":"Scan Timeout","ignoreCase":"key"},"failOnAccessibilityError":{"type":"boolean","description":"Fail on Accessibility Error","ignoreCase":"key"},"baselineFile":{"type":"string","description":"Baseline File Path","ignoreCase":"key"},"singleWorker":{"type":"boolean","description":"Uses a single crawler worker.","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Upload Azure DevOps Drop\n\nUploads a Folder to the Azure DevOps Drop Service","ignoreCase":"value","pattern":"^MicroBuildUploadVstsDropFolder@2$"},"inputs":{"description":"MicroBuild Upload Azure DevOps Drop inputs","properties":{"DropFolder":{"type":"string","description":"Drop Folder","ignoreCase":"key"},"DropName":{"type":"string","description":"Drop Name","ignoreCase":"key"},"AccessToken":{"type":"string","description":"Drop Service Access Token","ignoreCase":"key"},"DropServiceUri":{"type":"string","description":"Drop Service Uri","ignoreCase":"key"},"VSDropServiceUri":{"type":"string","description":"VSDrop Service Uri","ignoreCase":"key"}},"additionalProperties":false,"required":["DropFolder"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Upload Azure DevOps Drop\n\nUploads a Folder to the Azure DevOps Drop Service","ignoreCase":"value","pattern":"^MicroBuildUploadVstsDropFolder@1$"},"inputs":{"description":"MicroBuild Upload Azure DevOps Drop inputs","properties":{"DropFolder":{"type":"string","description":"Drop Folder","ignoreCase":"key"},"DropName":{"type":"string","description":"Drop Name","ignoreCase":"key"},"AccessToken":{"type":"string","description":"Drop Service Access Token","ignoreCase":"key"},"DropServiceUri":{"type":"string","description":"Drop Service Uri","ignoreCase":"key"},"VSDropServiceUri":{"type":"string","description":"VSDrop Service Uri","ignoreCase":"key"}},"additionalProperties":false,"required":["DropFolder"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Service Fabric PowerShell\n\nRun a PowerShell script in the context of an Azure Service Fabric cluster connection","ignoreCase":"value","pattern":"^ServiceFabricPowerShell@1$"},"inputs":{"description":"Service Fabric PowerShell inputs","properties":{"clusterConnection":{"type":"string","description":"Cluster Service Connection","ignoreCase":"key","aliases":["serviceConnectionName"]},"ScriptType":{"description":"Script Type","ignoreCase":"all","enum":["FilePath","InlineScript"]},"ScriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"Inline":{"type":"string","description":"Inline Script","ignoreCase":"key"},"ScriptArguments":{"type":"string","description":"Script Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":["clusterConnection"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Visual Studio Test\n\nRun tests with Visual Studio test runner","ignoreCase":"value","pattern":"^VSTest@1$"},"inputs":{"description":"Visual Studio Test inputs","properties":{"testAssembly":{"type":"string","description":"Test Assembly","ignoreCase":"key"},"testFiltercriteria":{"type":"string","description":"Test Filter criteria","ignoreCase":"key"},"runSettingsFile":{"type":"string","description":"Run Settings File","ignoreCase":"key"},"overrideTestrunParameters":{"type":"string","description":"Override TestRun Parameters","ignoreCase":"key"},"codeCoverageEnabled":{"type":"boolean","description":"Code Coverage Enabled","ignoreCase":"key"},"runInParallel":{"type":"boolean","description":"Run In Parallel","ignoreCase":"key"},"vstestLocationMethod":{"description":"VSTest","ignoreCase":"all","enum":["version","location"]},"vsTestVersion":{"description":"VSTest version","ignoreCase":"all","enum":["latest","14.0","12.0"]},"vstestLocation":{"type":"string","description":"Path to vstest.console.exe","ignoreCase":"key"},"pathtoCustomTestAdapters":{"type":"string","description":"Path to Custom Test Adapters","ignoreCase":"key"},"otherConsoleOptions":{"type":"string","description":"Other console options","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test Run Title","ignoreCase":"key"},"platform":{"type":"string","description":"Platform","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"publishRunAttachments":{"type":"boolean","description":"Upload Test Attachments","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Visual Studio Test\n\nRun unit and functional tests (Selenium, Appium, Coded UI test, etc.) using the Visual Studio Test (VsTest) runner. Test frameworks that have a Visual Studio test adapter such as MsTest, xUnit, NUnit, Chutzpah (for JavaScript tests using QUnit, Mocha and Jasmine), etc. can be run. Tests can be distributed on multiple agents using this task (version 2).","ignoreCase":"value","pattern":"^VSTest@2$"},"inputs":{"description":"Visual Studio Test inputs","properties":{"testSelector":{"description":"Select tests using","ignoreCase":"all","enum":["testAssemblies","testPlan","testRun"]},"testAssemblyVer2":{"type":"string","description":"Test files","ignoreCase":"key"},"testPlan":{"type":"string","description":"Test plan","ignoreCase":"key"},"testSuite":{"type":"string","description":"Test suite","ignoreCase":"key"},"testConfiguration":{"type":"string","description":"Test configuration","ignoreCase":"key"},"tcmTestRun":{"type":"string","description":"Test Run","ignoreCase":"key"},"searchFolder":{"type":"string","description":"Search folder","ignoreCase":"key"},"resultsFolder":{"type":"string","description":"Test results folder","ignoreCase":"key"},"testFiltercriteria":{"type":"string","description":"Test filter criteria","ignoreCase":"key"},"runOnlyImpactedTests":{"type":"boolean","description":"Run only impacted tests","ignoreCase":"key"},"runAllTestsAfterXBuilds":{"type":"string","description":"Number of builds after which all tests should be run","ignoreCase":"key"},"uiTests":{"type":"boolean","description":"Test mix contains UI tests","ignoreCase":"key"},"vstestLocationMethod":{"description":"Select test platform using","ignoreCase":"all","enum":["version","location"]},"vsTestVersion":{"description":"Test platform version","ignoreCase":"all","enum":["latest","16.0","15.0","14.0","toolsInstaller"]},"vstestLocation":{"type":"string","description":"Path to vstest.console.exe","ignoreCase":"key"},"runSettingsFile":{"type":"string","description":"Settings file","ignoreCase":"key"},"overrideTestrunParameters":{"type":"string","description":"Override test run parameters","ignoreCase":"key"},"pathtoCustomTestAdapters":{"type":"string","description":"Path to custom test adapters","ignoreCase":"key"},"runInParallel":{"type":"boolean","description":"Run tests in parallel on multi-core machines","ignoreCase":"key"},"runTestsInIsolation":{"type":"boolean","description":"Run tests in isolation","ignoreCase":"key"},"codeCoverageEnabled":{"type":"boolean","description":"Code coverage enabled","ignoreCase":"key"},"otherConsoleOptions":{"type":"string","description":"Other console options","ignoreCase":"key"},"distributionBatchType":{"description":"Batch tests","ignoreCase":"all","enum":["basedOnTestCases","basedOnExecutionTime","basedOnAssembly"]},"batchingBasedOnAgentsOption":{"description":"Batch options","ignoreCase":"all","enum":["autoBatchSize","customBatchSize"]},"customBatchSizeValue":{"type":"string","description":"Number of tests per batch","ignoreCase":"key"},"batchingBasedOnExecutionTimeOption":{"description":"Batch options","ignoreCase":"all","enum":["autoBatchSize","customTimeBatchSize"]},"customRunTimePerBatchValue":{"type":"string","description":"Running time (sec) per batch","ignoreCase":"key"},"dontDistribute":{"type":"boolean","description":"Replicate tests instead of distributing when multiple agents are used in the job","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"},"platform":{"type":"string","description":"Build platform","ignoreCase":"key"},"configuration":{"type":"string","description":"Build configuration","ignoreCase":"key"},"publishRunAttachments":{"type":"boolean","description":"Upload test attachments","ignoreCase":"key"},"failOnMinTestsNotRun":{"type":"boolean","description":"Fail the task if a minimum number of tests are not run.","ignoreCase":"key"},"minimumExpectedTests":{"type":"string","description":"Minimum # of tests","ignoreCase":"key"},"diagnosticsEnabled":{"type":"boolean","description":"Collect advanced diagnostics in case of catastrophic failures","ignoreCase":"key"},"collectDumpOn":{"description":"Collect process dump and attach to test run report","ignoreCase":"all","enum":["onAbortOnly","always","never"]},"rerunFailedTests":{"type":"boolean","description":"Rerun failed tests","ignoreCase":"key"},"rerunType":{"description":"Do not rerun if test failures exceed specified threshold","ignoreCase":"all","enum":["basedOnTestFailurePercentage","basedOnTestFailureCount"]},"rerunFailedThreshold":{"type":"string","description":"% failure","ignoreCase":"key"},"rerunFailedTestCasesMaxLimit":{"type":"string","description":"# of failed tests","ignoreCase":"key"},"rerunMaxAttempts":{"type":"string","description":"Maximum # of attempts","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Manual validation\n\n[PREVIEW] Pause a pipeline run to wait for manual interaction. Works only with YAML pipelines.","ignoreCase":"value","pattern":"^ManualValidation@0$"},"inputs":{"description":"Manual validation inputs","properties":{"notifyUsers":{"type":"string","description":"Notify users","ignoreCase":"key"},"instructions":{"type":"string","description":"Instructions","ignoreCase":"key"},"onTimeout":{"description":"On timeout","ignoreCase":"all","enum":["reject","resume"]}},"additionalProperties":false,"required":["notifyUsers"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Promote Nuget Packages\n\nPromote nuget packages to a view in VS and VS-CoreXTFeeds","ignoreCase":"value","pattern":"^MicroBuildPromoteNugetPackages@2$"},"inputs":{"description":"MicroBuild Promote Nuget Packages inputs","properties":{"AccessToken":{"type":"string","description":"Access Token to Modify the Feed","ignoreCase":"key"},"PackageConfigFiles":{"type":"string","description":"Full Paths of Packages Config Files","ignoreCase":"key"},"SolutionFiles":{"type":"string","description":"Full Path of Solution Files Containing Package References","ignoreCase":"key"},"View":{"type":"string","description":"View Name","ignoreCase":"key"}},"additionalProperties":false,"required":["View"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Ant\n\nBuild with Apache Ant","ignoreCase":"value","pattern":"^Ant@1$"},"inputs":{"description":"Ant inputs","properties":{"buildFile":{"type":"string","description":"Ant build file","ignoreCase":"key","aliases":["antBuildFile"]},"options":{"type":"string","description":"Options","ignoreCase":"key"},"targets":{"type":"string","description":"Target(s)","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to Azure Pipelines","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test results files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test run title","ignoreCase":"key"},"codeCoverageToolOptions":{"description":"Code coverage tool","ignoreCase":"all","enum":["None","Cobertura","JaCoCo"],"aliases":["codeCoverageTool"]},"codeCoverageClassFilesDirectories":{"type":"string","description":"Class files directories","ignoreCase":"key","aliases":["classFilesDirectories"]},"codeCoverageClassFilter":{"type":"string","description":"Class inclusion/exclusion filters","ignoreCase":"key","aliases":["classFilter"]},"codeCoverageSourceDirectories":{"type":"string","description":"Source files directories","ignoreCase":"key","aliases":["srcDirectories"]},"codeCoverageFailIfEmpty":{"type":"boolean","description":"Fail when code coverage results are missing","ignoreCase":"key","aliases":["failIfCoverageEmpty"]},"antHomeDirectory":{"type":"string","description":"Set ANT_HOME path","ignoreCase":"key","aliases":["antHomeUserInputPath"]},"javaHomeOption":{"description":"Set JAVA_HOME by","ignoreCase":"all","enum":["JDKVersion","Path"],"aliases":["javaHomeSelection"]},"jdkVersionOption":{"description":"JDK version","ignoreCase":"all","enum":["default","1.11","1.10","1.9","1.8","1.7","1.6"],"aliases":["jdkVersion"]},"jdkUserInputDirectory":{"type":"string","description":"JDK path","ignoreCase":"key","aliases":["jdkUserInputPath"]},"jdkArchitectureOption":{"description":"JDK architecture","ignoreCase":"all","enum":["x86","x64"],"aliases":["jdkArchitecture"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Visual Studio test agent deployment\n\nDeprecated: Instead, use the 'Visual Studio Test' task to run unit and functional tests","ignoreCase":"value","pattern":"^DeployVisualStudioTestAgent@2$"},"inputs":{"description":"Visual Studio test agent deployment inputs","properties":{"testMachines":{"type":"string","description":"Machines","ignoreCase":"key"},"adminUserName":{"type":"string","description":"Admin login","ignoreCase":"key"},"adminPassword":{"type":"string","description":"Admin password","ignoreCase":"key"},"winRmProtocol":{"description":"Protocol","ignoreCase":"all","enum":["Http","Https"]},"testCertificate":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"},"machineUserName":{"type":"string","description":"Username","ignoreCase":"key"},"machinePassword":{"type":"string","description":"Password","ignoreCase":"key"},"runAsProcess":{"type":"boolean","description":"Run UI tests","ignoreCase":"key"},"isDataCollectionOnly":{"type":"boolean","description":"Enable data collection only","ignoreCase":"key"},"testPlatform":{"description":"Test agent version","ignoreCase":"all","enum":["15.0","14.0"]},"agentLocation":{"type":"string","description":"Test agent location","ignoreCase":"key"},"updateTestAgent":{"type":"boolean","description":"Update test agent","ignoreCase":"key"}},"additionalProperties":false,"required":["testMachines","adminUserName","adminPassword","machineUserName","machinePassword"]}},"deprecationMessage":"DeployVisualStudioTestAgent is deprecated - Deprecated: Instead, use the 'Visual Studio Test' task to run unit and functional tests","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Visual Studio Test Agent Deployment\n\nDeploy and configure Test Agent to run tests on a set of machines","ignoreCase":"value","pattern":"^DeployVisualStudioTestAgent@1$"},"inputs":{"description":"Visual Studio Test Agent Deployment inputs","properties":{"testMachineGroup":{"type":"string","description":"Machines","ignoreCase":"key"},"adminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"adminPassword":{"type":"string","description":"Admin Password","ignoreCase":"key"},"winRmProtocol":{"description":"Protocol","ignoreCase":"all","enum":["Http","Https"]},"testCertificate":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"},"resourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"testMachines":{"type":"string","description":"Filter Criteria","ignoreCase":"key"},"machineUserName":{"type":"string","description":"Username","ignoreCase":"key"},"machinePassword":{"type":"string","description":"Password","ignoreCase":"key"},"runAsProcess":{"type":"boolean","description":"Interactive Process","ignoreCase":"key"},"agentLocation":{"type":"string","description":"Test Agent Location","ignoreCase":"key"},"updateTestAgent":{"type":"boolean","description":"Update Test Agent","ignoreCase":"key"},"isDataCollectionOnly":{"type":"boolean","description":"Enable Data Collection Only","ignoreCase":"key"}},"additionalProperties":false,"required":["testMachineGroup","machineUserName","machinePassword"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Conda environment\n\nThis task is deprecated. Use `conda` directly in script to work with Anaconda environments.","ignoreCase":"value","pattern":"^CondaEnvironment@1$"},"inputs":{"description":"Conda environment inputs","properties":{"createCustomEnvironment":{"type":"boolean","description":"Create a custom environment","ignoreCase":"key"},"environmentName":{"type":"string","description":"Environment name","ignoreCase":"key"},"packageSpecs":{"type":"string","description":"Package specs","ignoreCase":"key"},"updateConda":{"type":"boolean","description":"Update to the latest Conda","ignoreCase":"key"},"installOptions":{"type":"string","description":"Other options for `conda install`","ignoreCase":"key"},"createOptions":{"type":"string","description":"Other options for `conda create`","ignoreCase":"key"},"cleanEnvironment":{"type":"boolean","description":"Clean the environment","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"deprecationMessage":"CondaEnvironment is deprecated - This task is deprecated. Use `conda` directly in script to work with Anaconda environments.","doNotSuggest":true,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Conda environment\n\nCreate and activate a Conda environment","ignoreCase":"value","pattern":"^CondaEnvironment@0$"},"inputs":{"description":"Conda environment inputs","properties":{"environmentName":{"type":"string","description":"Environment name","ignoreCase":"key"},"packageSpecs":{"type":"string","description":"Package specs","ignoreCase":"key"},"updateConda":{"type":"boolean","description":"Update to the latest Conda","ignoreCase":"key"},"createOptions":{"type":"string","description":"Environment creation options","ignoreCase":"key"},"cleanEnvironment":{"type":"boolean","description":"Clean the environment","ignoreCase":"key"}},"additionalProperties":false,"required":["environmentName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Batch script\n\nRun a Windows command or batch script and optionally allow it to change the environment","ignoreCase":"value","pattern":"^BatchScript@1$"},"inputs":{"description":"Batch script inputs","properties":{"filename":{"type":"string","description":"Path","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"modifyEnvironment":{"type":"boolean","description":"Modify Environment","ignoreCase":"key"},"workingFolder":{"type":"string","description":"Working folder","ignoreCase":"key"},"failOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"}},"additionalProperties":false,"required":["filename"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Download Github Npm Package\n\nInstall npm packages from GitHub.","ignoreCase":"value","pattern":"^DownloadGithubNpmPackage@1$"},"inputs":{"description":"Download Github Npm Package inputs","properties":{"packageName":{"type":"string","description":"Package Name","ignoreCase":"key"},"version":{"type":"string","description":"Package Version","ignoreCase":"key"},"externalRegistryCredentials":{"type":"string","description":"Credentials for registry from GitHub","ignoreCase":"key","aliases":["externalEndpoints"]},"installDirectory":{"type":"string","description":"Destination directory","ignoreCase":"key","aliases":["packagesDirectory"]}},"additionalProperties":false,"required":["packageName","version","externalRegistryCredentials"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Visual Studio build\n\nBuild with MSBuild and set the Visual Studio version property","ignoreCase":"value","pattern":"^VSBuild@1$"},"inputs":{"description":"Visual Studio build inputs","properties":{"solution":{"type":"string","description":"Solution","ignoreCase":"key"},"vsVersion":{"description":"Visual Studio Version","ignoreCase":"all","enum":["latest","17.0","16.0","15.0","14.0","12.0","11.0"]},"msbuildArgs":{"type":"string","description":"MSBuild Arguments","ignoreCase":"key"},"platform":{"type":"string","description":"Platform","ignoreCase":"key"},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"clean":{"type":"boolean","description":"Clean","ignoreCase":"key"},"maximumCpuCount":{"type":"boolean","description":"Build in Parallel","ignoreCase":"key"},"restoreNugetPackages":{"type":"boolean","description":"Restore NuGet Packages","ignoreCase":"key"},"msbuildArchitecture":{"description":"MSBuild Architecture","ignoreCase":"all","enum":["x86","x64"]},"logProjectEvents":{"type":"boolean","description":"Record Project Details","ignoreCase":"key"},"createLogFile":{"type":"boolean","description":"Create Log File","ignoreCase":"key"},"logFileVerbosity":{"description":"Log File Verbosity","ignoreCase":"all","enum":["quiet","minimal","normal","detailed","diagnostic"]},"enableDefaultLogger":{"type":"boolean","description":"Enable Default Logger","ignoreCase":"key"},"customVersion":{"type":"string","description":"Custom Version","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure Key Vault\n\nDownload Azure Key Vault secrets","ignoreCase":"value","pattern":"^AzureKeyVault@1$"},"inputs":{"description":"Azure Key Vault inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"KeyVaultName":{"type":"string","description":"Key vault","ignoreCase":"key"},"SecretsFilter":{"description":"Secrets filter","ignoreCase":"all","enum":["EditableOptions"]},"RunAsPreJob":{"description":"Make secrets available to whole job","ignoreCase":"all","enum":["EditableOptions"]}},"additionalProperties":false,"required":["azureSubscription","KeyVaultName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure Key Vault\n\nDownload Azure Key Vault secrets","ignoreCase":"value","pattern":"^AzureKeyVault@2$"},"inputs":{"description":"Azure Key Vault inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"KeyVaultName":{"type":"string","description":"Key vault","ignoreCase":"key"},"SecretsFilter":{"description":"Secrets filter","ignoreCase":"all","enum":["EditableOptions"]},"RunAsPreJob":{"description":"Make secrets available to whole job","ignoreCase":"all","enum":["EditableOptions"]}},"additionalProperties":false,"required":["azureSubscription","KeyVaultName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":".NET Core sdk/runtime installer\n\nAcquire a specific version of the .NET Core SDK from the internet or local cache and add it to the PATH","ignoreCase":"value","pattern":"^DotNetCoreInstaller@1$"},"inputs":{"description":".NET Core sdk/runtime installer inputs","properties":{"packageType":{"description":"Package to install","ignoreCase":"all","enum":["runtime","sdk"]},"version":{"type":"string","description":"Version","ignoreCase":"key"},"includePreviewVersions":{"type":"boolean","description":"Include Preview Versions","ignoreCase":"key"},"installationPath":{"type":"string","description":"Path To Install .Net Core","ignoreCase":"key"},"performMultiLevelLookup":{"type":"boolean","description":"Perform Multi Level Lookup","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"deprecationMessage":"DotNetCoreInstaller is deprecated - Acquire a specific version of the .NET Core SDK from the internet or local cache and add it to the PATH","doNotSuggest":true,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Use .NET Core\n\nAcquires a specific version of the .NET Core SDK from the internet or the local cache and adds it to the PATH. Use this task to change the version of .NET Core used in subsequent tasks. Additionally provides proxy support.","ignoreCase":"value","pattern":"^UseDotNet@2$"},"inputs":{"description":"Use .NET Core inputs","properties":{"packageType":{"description":"Package to install","ignoreCase":"all","enum":["runtime","sdk"]},"useGlobalJson":{"type":"boolean","description":"Use global json","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key"},"version":{"type":"string","description":"Version","ignoreCase":"key"},"vsVersion":{"type":"string","description":"Compatible Visual Studio version","ignoreCase":"key"},"includePreviewVersions":{"type":"boolean","description":"Include Preview Versions","ignoreCase":"key"},"installationPath":{"type":"string","description":"Path To Install .Net Core","ignoreCase":"key"},"performMultiLevelLookup":{"type":"boolean","description":"Perform Multi Level Lookup","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":".NET Core SDK/runtime installer\n\nAcquire a specific version of the .NET Core SDK from the internet or local cache and add it to the PATH","ignoreCase":"value","pattern":"^DotNetCoreInstaller@0$"},"inputs":{"description":".NET Core SDK/runtime installer inputs","properties":{"packageType":{"description":"Package to install","ignoreCase":"all","enum":["runtime","sdk"]},"version":{"type":"string","description":"Version","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure App Service manage\n\nStart, stop, restart, slot swap, slot delete, install site extensions or enable continuous monitoring for an Azure App Service","ignoreCase":"value","pattern":"^AzureAppServiceManage@0$"},"inputs":{"description":"Azure App Service manage inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"Action":{"description":"Action","ignoreCase":"all","enum":["Swap Slots","Start Azure App Service","Stop Azure App Service","Restart Azure App Service","Start Swap With Preview","Complete Swap","Cancel Swap","Delete Slot","Install Extensions","Enable Continuous Monitoring","Start all continuous webjobs","Stop all continuous webjobs"]},"WebAppName":{"type":"string","description":"App Service name","ignoreCase":"key"},"SpecifySlotOrASE":{"type":"boolean","description":"Specify Slot or App Service Environment","ignoreCase":"key","aliases":["SpecifySlot"]},"ResourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"SourceSlot":{"type":"string","description":"Source Slot","ignoreCase":"key"},"SwapWithProduction":{"type":"boolean","description":"Swap with Production","ignoreCase":"key"},"TargetSlot":{"type":"string","description":"Target Slot","ignoreCase":"key"},"PreserveVnet":{"type":"boolean","description":"Preserve Vnet","ignoreCase":"key"},"Slot":{"type":"string","description":"Slot","ignoreCase":"key"},"ExtensionsList":{"type":"string","description":"Install Extensions","ignoreCase":"key"},"OutputVariable":{"type":"string","description":"Output variable","ignoreCase":"key"},"AppInsightsResourceGroupName":{"type":"string","description":"Resource Group name for Application Insights","ignoreCase":"key"},"ApplicationInsightsResourceName":{"type":"string","description":"Application Insights resource name","ignoreCase":"key"},"ApplicationInsightsWebTestName":{"type":"string","description":"Application Insights web test name","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","WebAppName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Install Azure Func Core Tools\n\nInstall Azure Func Core Tools","ignoreCase":"value","pattern":"^FuncToolsInstaller@0$"},"inputs":{"description":"Install Azure Func Core Tools inputs","properties":{"version":{"type":"string","description":"Version","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"File transform\n\nReplace tokens with variable values in XML or JSON configuration files","ignoreCase":"value","pattern":"^FileTransform@1$"},"inputs":{"description":"File transform inputs","properties":{"folderPath":{"type":"string","description":"Package or folder","ignoreCase":"key"},"enableXmlTransform":{"type":"boolean","description":"XML transformation","ignoreCase":"key"},"xmlTransformationRules":{"type":"string","description":"Transformation rules","ignoreCase":"key"},"fileType":{"description":"File format","ignoreCase":"all","enum":["xml","json"]},"targetFiles":{"type":"string","description":"Target files","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"File transform\n\nReplace tokens with variable values in XML or JSON configuration files","ignoreCase":"value","pattern":"^FileTransform@2$"},"inputs":{"description":"File transform inputs","properties":{"folderPath":{"type":"string","description":"Package or folder","ignoreCase":"key"},"xmlTransformationRules":{"type":"string","description":"XML Transformation rules","ignoreCase":"key"},"jsonTargetFiles":{"type":"string","description":"JSON target files","ignoreCase":"key"},"xmlTargetFiles":{"type":"string","description":"XML target files","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Mac Codesign Verification\n\nVerifies that mac files have been correctly codesigned. This can only be used on Mac hosts.","ignoreCase":"value","pattern":"^MicroBuildMacSignVerify@0$"},"inputs":{"description":"MicroBuild Mac Codesign Verification inputs","properties":{"Directories":{"type":"string","description":"Directories to Verify","ignoreCase":"key"},"AppIdentity":{"type":"string","description":"Application ID","ignoreCase":"key"}},"additionalProperties":false,"required":["Directories","AppIdentity"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Extract files\n\nExtract a variety of archive and compression files such as .7z, .rar, .tar.gz, and .zip","ignoreCase":"value","pattern":"^ExtractFiles@1$"},"inputs":{"description":"Extract files inputs","properties":{"archiveFilePatterns":{"type":"string","description":"Archive file patterns","ignoreCase":"key"},"destinationFolder":{"type":"string","description":"Destination folder","ignoreCase":"key"},"cleanDestinationFolder":{"type":"boolean","description":"Clean destination folder before extracting","ignoreCase":"key"},"overwriteExistingFiles":{"type":"boolean","description":"Overwrite existing files","ignoreCase":"key"},"pathToSevenZipTool":{"type":"string","description":"Path to 7z utility","ignoreCase":"key"}},"additionalProperties":false,"required":["destinationFolder"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Xamarin.Android\n\nBuild an Android app with Xamarin","ignoreCase":"value","pattern":"^XamarinAndroid@1$"},"inputs":{"description":"Xamarin.Android inputs","properties":{"projectFile":{"type":"string","description":"Project","ignoreCase":"key","aliases":["project"]},"target":{"type":"string","description":"Target","ignoreCase":"key"},"outputDirectory":{"type":"string","description":"Output directory","ignoreCase":"key","aliases":["outputDir"]},"configuration":{"type":"string","description":"Configuration","ignoreCase":"key"},"createAppPackage":{"type":"boolean","description":"Create app package","ignoreCase":"key"},"clean":{"type":"boolean","description":"Clean","ignoreCase":"key"},"msbuildLocationOption":{"description":"MSBuild","ignoreCase":"all","enum":["version","location"],"aliases":["msbuildLocationMethod"]},"msbuildVersionOption":{"description":"MSBuild version","ignoreCase":"all","enum":["latest","17.0","16.0","15.0","14.0","12.0","4.0"],"aliases":["msbuildVersion"]},"msbuildFile":{"type":"string","description":"MSBuild location","ignoreCase":"key","aliases":["msbuildLocation"]},"msbuildArchitectureOption":{"description":"MSBuild architecture","ignoreCase":"all","enum":["x86","x64"],"aliases":["msbuildArchitecture"]},"msbuildArguments":{"type":"string","description":"Additional arguments","ignoreCase":"key"},"jdkOption":{"description":"Select JDK to use for the build","ignoreCase":"all","enum":["JDKVersion","Path"],"aliases":["jdkSelection"]},"jdkVersionOption":{"description":"JDK version","ignoreCase":"all","enum":["default","1.11","1.10","1.9","1.8","1.7","1.6"],"aliases":["jdkVersion"]},"jdkDirectory":{"type":"string","description":"JDK path","ignoreCase":"key","aliases":["jdkUserInputPath"]},"jdkArchitectureOption":{"description":"JDK architecture","ignoreCase":"all","enum":["x86","x64"],"aliases":["jdkArchitecture"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Manifest Generator Task\n\nCreates a manifest.json and bsi.json for all the files in a folder. This generated manifest can be used to validate the contents of the folder in the future.","ignoreCase":"value","pattern":"^ManifestGeneratorTask@0$"},"inputs":{"description":"Manifest Generator Task inputs","properties":{"BuildDropPath":{"type":"string","description":"The root folder for which the manifest has to be generated.","ignoreCase":"key"},"ManifestDirPath":{"type":"string","description":"The path of the directory where the generated manifest files will be placed. If this parameter is not specified, the files will be placed in {BuildDropPath}/_manifest directory.","ignoreCase":"key"},"BuildComponentPath":{"type":"string","description":"The folder that contains the build's components/packages.","ignoreCase":"key"},"Verbosity":{"description":"The verbosity of the output generated by the manifest generator.","ignoreCase":"all","enum":["Verbose","Debug","Information","Warning","Error","Fatal"]},"PackageName":{"type":"string","description":"The name of the package this SBOM describes.","ignoreCase":"key"},"PackageVersion":{"type":"string","description":"The version of the package this SBOM describes.","ignoreCase":"key"},"DockerImagesToScan":{"type":"string","description":"Comma separated list of docker image names or hashes to be scanned for packages, ex: ubuntu:16.04, 56bab49eef2ef07505f6a1b0d5bd3a601dfc3c76ad4460f24c91d6fa298369ab.","ignoreCase":"key"},"ConfigFilePath":{"type":"string","description":"The json file that contains the configuration for the Manifest Tool.","ignoreCase":"key"}},"additionalProperties":false,"required":["BuildDropPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Powershell++ (deprecated)\n\n(Deprecated) Use the PowerShell task version 2 for online scripts","ignoreCase":"value","pattern":"^Powershellpp@0$"},"inputs":{"description":"Powershell++ (deprecated) inputs","properties":{"type":{"description":"Type","ignoreCase":"all","enum":["InlineScript","FilePath"]},"scriptName":{"type":"string","description":"Script filename","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingFolder":{"type":"string","description":"Working folder","ignoreCase":"key"},"script":{"type":"string","description":"Script","ignoreCase":"key"}},"additionalProperties":false,"required":["type"]}},"deprecationMessage":"Powershellpp is deprecated - (Deprecated) Use the PowerShell task version 2 for online scripts","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Copy and Publish Build Artifacts\n\n[DEPRECATED] Use the Copy Files task and the Publish Build Artifacts task instead","ignoreCase":"value","pattern":"^CopyPublishBuildArtifacts@1$"},"inputs":{"description":"Copy and Publish Build Artifacts inputs","properties":{"CopyRoot":{"type":"string","description":"Copy Root","ignoreCase":"key"},"Contents":{"type":"string","description":"Contents","ignoreCase":"key"},"ArtifactName":{"type":"string","description":"Artifact Name","ignoreCase":"key"},"ArtifactType":{"description":"Artifact Type","ignoreCase":"all","enum":["Container","FilePath"]},"TargetPath":{"type":"string","description":"Path","ignoreCase":"key"}},"additionalProperties":false,"required":["Contents","ArtifactName","ArtifactType"]}},"deprecationMessage":"CopyPublishBuildArtifacts is deprecated - [DEPRECATED] Use the Copy Files task and the Publish Build Artifacts task instead","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Bash or CMD\n\nExecute Bash on POSIX, CMD on Windows","ignoreCase":"value","pattern":"^BashOrCmd@0$"},"inputs":{"description":"Bash or CMD inputs","properties":{"bash":{"type":"string","description":"Bash script","ignoreCase":"key"},"cmd":{"type":"string","description":"CMD script","ignoreCase":"key"}},"additionalProperties":false,"required":["bash","cmd"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Download package\n\nDownload a package from a package management feed in Azure Artifacts","ignoreCase":"value","pattern":"^DownloadPackage@1$"},"inputs":{"description":"Download package inputs","properties":{"packageType":{"description":"Package Type","ignoreCase":"all","enum":["maven","npm","nuget","pypi","upack"]},"feed":{"type":"string","description":"Feed","ignoreCase":"key"},"view":{"type":"string","description":"View","ignoreCase":"key"},"definition":{"type":"string","description":"Package","ignoreCase":"key"},"version":{"type":"string","description":"Version","ignoreCase":"key"},"files":{"type":"string","description":"Files","ignoreCase":"key"},"extract":{"type":"boolean","description":"Extract package contents","ignoreCase":"key"},"downloadPath":{"type":"string","description":"Destination directory","ignoreCase":"key"}},"additionalProperties":false,"required":["feed","definition","version"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Download package\n\nDownload a package from a package management feed in Azure Artifacts","ignoreCase":"value","pattern":"^DownloadPackage@0$"},"inputs":{"description":"Download package inputs","properties":{"feed":{"type":"string","description":"Feed","ignoreCase":"key"},"definition":{"type":"string","description":"Package","ignoreCase":"key"},"version":{"type":"string","description":"Version","ignoreCase":"key"},"downloadPath":{"type":"string","description":"Destination directory","ignoreCase":"key"}},"additionalProperties":false,"required":["feed","definition","version"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Static Drop\n\nThis task is deprecated.","ignoreCase":"value","pattern":"^MicroBuildStaticDrop@1$"},"inputs":{"description":"MicroBuild Static Drop inputs","properties":{"CopyRoot":{"type":"string","description":"Copy Root","ignoreCase":"key"},"Contents":{"type":"string","description":"Contents","ignoreCase":"key"},"ArtifactName":{"type":"string","description":"Artifact Name","ignoreCase":"key"},"TargetPath":{"type":"string","description":"Path","ignoreCase":"key"}},"additionalProperties":false,"required":["Contents"]}},"deprecationMessage":"MicroBuildStaticDrop is deprecated - This task is deprecated.","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure resource group deployment\n\nDeploy an Azure Resource Manager (ARM) template to a resource group and manage virtual machines","ignoreCase":"value","pattern":"^AzureResourceGroupDeployment@2$"},"inputs":{"description":"Azure resource group deployment inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"action":{"description":"Action","ignoreCase":"all","enum":["Create Or Update Resource Group","Select Resource Group","Start","Stop","StopWithDeallocate","Restart","Delete","DeleteRG"]},"resourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"location":{"type":"string","description":"Location","ignoreCase":"key"},"templateLocation":{"description":"Template location","ignoreCase":"all","enum":["Linked artifact","URL of the file"]},"csmFileLink":{"type":"string","description":"Template link","ignoreCase":"key"},"csmParametersFileLink":{"type":"string","description":"Template parameters link","ignoreCase":"key"},"csmFile":{"type":"string","description":"Template","ignoreCase":"key"},"csmParametersFile":{"type":"string","description":"Template parameters","ignoreCase":"key"},"overrideParameters":{"type":"string","description":"Override template parameters","ignoreCase":"key"},"deploymentMode":{"description":"Deployment mode","ignoreCase":"all","enum":["Incremental","Complete","Validation"]},"enableDeploymentPrerequisites":{"description":"Enable prerequisites","ignoreCase":"all","enum":["None","ConfigureVMwithWinRM","ConfigureVMWithDGAgent"]},"teamServicesConnection":{"type":"string","description":"Azure Pipelines service connection","ignoreCase":"key","aliases":["deploymentGroupEndpoint"]},"teamProject":{"type":"string","description":"Team project","ignoreCase":"key","aliases":["project"]},"deploymentGroupName":{"type":"string","description":"Deployment Group","ignoreCase":"key"},"copyAzureVMTags":{"type":"boolean","description":"Copy Azure VM tags to agents","ignoreCase":"key"},"runAgentServiceAsUser":{"type":"boolean","description":"Run agent service as a user","ignoreCase":"key"},"userName":{"type":"string","description":"User name","ignoreCase":"key"},"password":{"type":"string","description":"Password","ignoreCase":"key"},"outputVariable":{"type":"string","description":"VM details for WinRM","ignoreCase":"key"},"deploymentName":{"type":"string","description":"Deployment name","ignoreCase":"key"},"deploymentOutputs":{"type":"string","description":"Deployment outputs","ignoreCase":"key"},"addSpnToEnvironment":{"type":"boolean","description":"Access service principal details in override parameters","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","resourceGroupName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure Resource Group Deployment\n\nDeploy, start, stop, delete Azure Resource Groups","ignoreCase":"value","pattern":"^AzureResourceGroupDeployment@1$"},"inputs":{"description":"Azure Resource Group Deployment inputs","properties":{"ConnectedServiceNameSelector":{"description":"Azure Connection Type","ignoreCase":"all","enum":["ConnectedServiceName","ConnectedServiceNameClassic"]},"ConnectedServiceName":{"type":"string","description":"Azure Subscription","ignoreCase":"key"},"ConnectedServiceNameClassic":{"type":"string","description":"Azure Classic Subscription","ignoreCase":"key"},"action":{"description":"Action","ignoreCase":"all","enum":["Create Or Update Resource Group","Select Resource Group","Start","Stop","Restart","Delete","DeleteRG"]},"actionClassic":{"description":"Action","ignoreCase":"all","enum":["Select Resource Group"]},"resourceGroupName":{"type":"string","description":"Resource Group","ignoreCase":"key"},"cloudService":{"type":"string","description":"Cloud Service","ignoreCase":"key"},"location":{"description":"Location","ignoreCase":"all","enum":["Australia East","Australia Southeast","Brazil South","Canada Central","Canada East","Central India","Central US","East Asia","East US","East US 2 ","Japan East","Japan West","North Central US","North Europe","South Central US","South India","Southeast Asia","UK South","UK West","West Central US","West Europe","West India","West US","West US 2"]},"csmFile":{"type":"string","description":"Template","ignoreCase":"key"},"csmParametersFile":{"type":"string","description":"Template Parameters","ignoreCase":"key"},"overrideParameters":{"type":"string","description":"Override Template Parameters","ignoreCase":"key"},"deploymentMode":{"description":"Deployment Mode","ignoreCase":"all","enum":["Validation","Incremental","Complete"]},"enableDeploymentPrerequisitesForCreate":{"type":"boolean","description":"Enable Deployment Prerequisites","ignoreCase":"key"},"enableDeploymentPrerequisitesForSelect":{"type":"boolean","description":"Enable Deployment Prerequisites","ignoreCase":"key"},"outputVariable":{"type":"string","description":"Resource Group","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"deprecationMessage":"AzureResourceGroupDeployment is deprecated - Deploy, start, stop, delete Azure Resource Groups","doNotSuggest":true,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"ARM template deployment\n\nDeploy an Azure Resource Manager (ARM) template to all the deployment scopes","ignoreCase":"value","pattern":"^AzureResourceManagerTemplateDeployment@3$"},"inputs":{"description":"ARM template deployment inputs","properties":{"deploymentScope":{"description":"Deployment scope","ignoreCase":"all","enum":["Management Group","Subscription","Resource Group"]},"azureResourceManagerConnection":{"type":"string","description":"Azure Resource Manager connection","ignoreCase":"key","aliases":["ConnectedServiceName"]},"subscriptionId":{"type":"string","description":"Subscription","ignoreCase":"key","aliases":["subscriptionName"]},"action":{"description":"Action","ignoreCase":"all","enum":["Create Or Update Resource Group","DeleteRG"]},"resourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"location":{"type":"string","description":"Location","ignoreCase":"key"},"templateLocation":{"description":"Template location","ignoreCase":"all","enum":["Linked artifact","URL of the file"]},"csmFileLink":{"type":"string","description":"Template link","ignoreCase":"key"},"csmParametersFileLink":{"type":"string","description":"Template parameters link","ignoreCase":"key"},"csmFile":{"type":"string","description":"Template","ignoreCase":"key"},"csmParametersFile":{"type":"string","description":"Template parameters","ignoreCase":"key"},"overrideParameters":{"type":"string","description":"Override template parameters","ignoreCase":"key"},"deploymentMode":{"description":"Deployment mode","ignoreCase":"all","enum":["Incremental","Complete","Validation"]},"deploymentName":{"type":"string","description":"Deployment name","ignoreCase":"key"},"deploymentOutputs":{"type":"string","description":"Deployment outputs","ignoreCase":"key"},"addSpnToEnvironment":{"type":"boolean","description":"Access service principal details in override parameters","ignoreCase":"key"}},"additionalProperties":false,"required":["azureResourceManagerConnection"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Invoke REST API\n\nInvoke REST API as a part of your process.","ignoreCase":"value","pattern":"^InvokeRESTAPI@0$"},"inputs":{"description":"Invoke REST API inputs","properties":{"serviceConnection":{"type":"string","description":"Generic endpoint","ignoreCase":"key","aliases":["connectedServiceName"]},"method":{"description":"Method","ignoreCase":"all","enum":["OPTIONS","GET","HEAD","POST","PUT","DELETE","TRACE","PATCH"]},"headers":{"type":"string","description":"Headers","ignoreCase":"key"},"body":{"type":"string","description":"Body","ignoreCase":"key"},"urlSuffix":{"type":"string","description":"Url suffix string","ignoreCase":"key"},"waitForCompletion":{"description":"Complete based on","ignoreCase":"all","enum":["true","false"]},"successCriteria":{"type":"string","description":"Success criteria","ignoreCase":"key"}},"additionalProperties":false,"required":["serviceConnection"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Invoke REST API\n\nInvoke a REST API as a part of your pipeline.","ignoreCase":"value","pattern":"^InvokeRESTAPI@1$"},"inputs":{"description":"Invoke REST API inputs","properties":{"connectionType":{"description":"Connection type","ignoreCase":"all","enum":["connectedServiceName","connectedServiceNameARM"],"aliases":["connectedServiceNameSelector"]},"serviceConnection":{"type":"string","description":"Generic service connection","ignoreCase":"key","aliases":["connectedServiceName","genericService"]},"azureServiceConnection":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["connectedServiceNameARM","azureSubscription"]},"method":{"description":"Method","ignoreCase":"all","enum":["OPTIONS","GET","HEAD","POST","PUT","DELETE","TRACE","PATCH"]},"headers":{"type":"string","description":"Headers","ignoreCase":"key"},"body":{"type":"string","description":"Body","ignoreCase":"key"},"urlSuffix":{"type":"string","description":"URL suffix and parameters","ignoreCase":"key"},"waitForCompletion":{"description":"Completion event","ignoreCase":"all","enum":["true","false"]},"successCriteria":{"type":"string","description":"Success criteria","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Archive Files\n\nArchive files using compression formats such as .7z, .rar, .tar.gz, and .zip.","ignoreCase":"value","pattern":"^ArchiveFiles@1$"},"inputs":{"description":"Archive Files inputs","properties":{"rootFolder":{"type":"string","description":"Root folder (or file) to archive","ignoreCase":"key"},"includeRootFolder":{"type":"boolean","description":"Prefix root folder name to archive paths","ignoreCase":"key"},"archiveType":{"description":"Archive type","ignoreCase":"all","enum":["default","7z","tar","wim"]},"tarCompression":{"description":"Tar compression","ignoreCase":"all","enum":["gz","bz2","xz","none"]},"archiveFile":{"type":"string","description":"Archive file to create","ignoreCase":"key"},"replaceExistingArchive":{"type":"boolean","description":"Replace existing archive","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Archive files\n\nCompress files into .7z, .tar.gz, or .zip","ignoreCase":"value","pattern":"^ArchiveFiles@2$"},"inputs":{"description":"Archive files inputs","properties":{"rootFolderOrFile":{"type":"string","description":"Root folder or file to archive","ignoreCase":"key"},"includeRootFolder":{"type":"boolean","description":"Prepend root folder name to archive paths","ignoreCase":"key"},"archiveType":{"description":"Archive type","ignoreCase":"all","enum":["zip","7z","tar","wim"]},"sevenZipCompression":{"description":"7z compression","ignoreCase":"all","enum":["ultra","maximum","normal","fast","fastest","none"]},"tarCompression":{"description":"Tar compression","ignoreCase":"all","enum":["gz","bz2","xz","none"]},"archiveFile":{"type":"string","description":"Archive file to create","ignoreCase":"key"},"replaceExistingArchive":{"type":"boolean","description":"Replace existing archive","ignoreCase":"key"},"verbose":{"type":"boolean","description":"Force verbose output","ignoreCase":"key"},"quiet":{"type":"boolean","description":"Force quiet output","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"GitHub Comment\n\nWrite a comment to your Github entity i.e. issue or a Pull Request (PR)","ignoreCase":"value","pattern":"^GitHubComment@0$"},"inputs":{"description":"GitHub Comment inputs","properties":{"gitHubConnection":{"type":"string","description":"GitHub connection (OAuth or PAT)","ignoreCase":"key"},"repositoryName":{"type":"string","description":"Repository","ignoreCase":"key"},"id":{"type":"string","description":"ID of the github pr/issue","ignoreCase":"key"},"comment":{"type":"string","description":"Comment","ignoreCase":"key"}},"additionalProperties":false,"required":["gitHubConnection"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Copy files\n\nCopy files from a source folder to a target folder using patterns matching file paths (not folder paths)","ignoreCase":"value","pattern":"^CopyFiles@2$"},"inputs":{"description":"Copy files inputs","properties":{"SourceFolder":{"type":"string","description":"Source Folder","ignoreCase":"key"},"Contents":{"type":"string","description":"Contents","ignoreCase":"key"},"TargetFolder":{"type":"string","description":"Target Folder","ignoreCase":"key"},"CleanTargetFolder":{"type":"boolean","description":"Clean Target Folder","ignoreCase":"key"},"OverWrite":{"type":"boolean","description":"Overwrite","ignoreCase":"key"},"flattenFolders":{"type":"boolean","description":"Flatten Folders","ignoreCase":"key"},"preserveTimestamp":{"type":"boolean","description":"Preserve Target Timestamp","ignoreCase":"key"},"retryCount":{"type":"string","description":"Retry count to copy the file","ignoreCase":"key"},"delayBetweenRetries":{"type":"string","description":"Delay between two retries.","ignoreCase":"key"},"ignoreMakeDirErrors":{"type":"boolean","description":"Ignore errors during creation of target folder.","ignoreCase":"key"}},"additionalProperties":false,"required":["TargetFolder"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Copy Files\n\nCopy files from source folder to target folder using minimatch patterns (The minimatch patterns will only match file paths, not folder paths)","ignoreCase":"value","pattern":"^CopyFiles@1$"},"inputs":{"description":"Copy Files inputs","properties":{"SourceFolder":{"type":"string","description":"Source Folder","ignoreCase":"key"},"Contents":{"type":"string","description":"Contents","ignoreCase":"key"},"TargetFolder":{"type":"string","description":"Target Folder","ignoreCase":"key"},"CleanTargetFolder":{"type":"boolean","description":"Clean Target Folder","ignoreCase":"key"},"OverWrite":{"type":"boolean","description":"Overwrite","ignoreCase":"key"},"flattenFolders":{"type":"boolean","description":"Flatten Folders","ignoreCase":"key"}},"additionalProperties":false,"required":["TargetFolder"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure Database for MySQL deployment\n\nRun your scripts and make changes to your Azure Database for MySQL","ignoreCase":"value","pattern":"^AzureMysqlDeployment@1$"},"inputs":{"description":"Azure Database for MySQL deployment inputs","properties":{"azureSubscription":{"type":"string","description":"Azure Subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"ServerName":{"type":"string","description":"Host Name","ignoreCase":"key"},"DatabaseName":{"type":"string","description":"Database Name","ignoreCase":"key"},"SqlUsername":{"type":"string","description":"Server Admin Login","ignoreCase":"key"},"SqlPassword":{"type":"string","description":"Password","ignoreCase":"key"},"TaskNameSelector":{"description":"Type","ignoreCase":"all","enum":["SqlTaskFile","InlineSqlTask"]},"SqlFile":{"type":"string","description":"MySQL Script","ignoreCase":"key"},"SqlInline":{"type":"string","description":"Inline MySQL Script","ignoreCase":"key"},"SqlAdditionalArguments":{"type":"string","description":"Additional MySQL Arguments","ignoreCase":"key"},"IpDetectionMethod":{"description":"Specify Firewall Rules Using","ignoreCase":"all","enum":["AutoDetect","IPAddressRange"]},"StartIpAddress":{"type":"string","description":"Start IP Address","ignoreCase":"key"},"EndIpAddress":{"type":"string","description":"End IP Address","ignoreCase":"key"},"DeleteFirewallRule":{"type":"boolean","description":"Delete Rule After Task Ends","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","ServerName","SqlUsername","SqlPassword"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"npm\n\nInstall and publish npm packages, or run an npm command. Supports npmjs.com and authenticated registries like Azure Artifacts.","ignoreCase":"value","pattern":"^Npm@1$"},"inputs":{"description":"npm inputs","properties":{"command":{"description":"Command","ignoreCase":"all","enum":["ci","install","publish","custom"]},"workingDir":{"type":"string","description":"Working folder that contains package.json","ignoreCase":"key"},"verbose":{"type":"boolean","description":"Verbose logging","ignoreCase":"key"},"customCommand":{"type":"string","description":"Command and arguments","ignoreCase":"key"},"customRegistry":{"description":"Registries to use","ignoreCase":"all","enum":["useNpmrc","useFeed"]},"customFeed":{"type":"string","description":"Use packages from this Azure Artifacts/TFS registry","ignoreCase":"key"},"customEndpoint":{"type":"string","description":"Credentials for registries outside this organization/collection","ignoreCase":"key"},"publishRegistry":{"description":"Registry location","ignoreCase":"all","enum":["useExternalRegistry","useFeed"]},"publishFeed":{"type":"string","description":"Target registry","ignoreCase":"key"},"publishPackageMetadata":{"type":"boolean","description":"Publish pipeline metadata","ignoreCase":"key"},"publishEndpoint":{"type":"string","description":"External Registry","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"npm\n\nRun an npm command. Use NpmAuthenticate@0 task for latest capabilities.","ignoreCase":"value","pattern":"^Npm@0$"},"inputs":{"description":"npm inputs","properties":{"cwd":{"type":"string","description":"working folder","ignoreCase":"key"},"command":{"type":"string","description":"npm command","ignoreCase":"key"},"arguments":{"type":"string","description":"arguments","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Drop Validator Task\n\nValidates a given drop against a manifest generated at build time to verify the integrity of the drop.","ignoreCase":"value","pattern":"^DropValidatorTask@0$"},"inputs":{"description":"Drop Validator Task inputs","properties":{"BuildDropPath":{"type":"string","description":"The root folder of the drop.","ignoreCase":"key"},"ManifestDirPath":{"type":"string","description":"The path of the directory where the manifest will be validated. If this parameter is not specified, the manifest will be validated in {BuildDropPath}/_manifest directory.","ignoreCase":"key"},"OutputPath":{"type":"string","description":"The path where the generated output file is placed.","ignoreCase":"key"},"ValidateSignature":{"type":"boolean","description":"If checked we will verify the signature of the manifest using the provided catalog file.","ignoreCase":"key"},"Verbosity":{"description":"The verbosity of the output generated by the drop validator.","ignoreCase":"all","enum":["Verbose","Debug","Information","Warning","Error","Fatal"]},"ConfigFilePath":{"type":"string","description":"The json file that contains the configuration for the Manifest Tool.","ignoreCase":"key"},"RootPathFilter":{"type":"string","description":"If you're downloading only a part of the drop using the '-r' or 'root' parameter in the drop client, specify the same string value here in order to skip validating paths that are not downloaded.","ignoreCase":"key"}},"additionalProperties":false,"required":["BuildDropPath","OutputPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Deploy Azure Static Web App\n\n[PREVIEW] Build and deploy an Azure Static Web App","ignoreCase":"value","pattern":"^AzureStaticWebApp@0$"},"inputs":{"description":"Deploy Azure Static Web App inputs","properties":{"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd","rootDirectory"]},"app_location":{"type":"string","description":"App location","ignoreCase":"key"},"app_build_command":{"type":"string","description":"App build command","ignoreCase":"key"},"output_location":{"type":"string","description":"Output location","ignoreCase":"key"},"api_location":{"type":"string","description":"Api location","ignoreCase":"key"},"api_build_command":{"type":"string","description":"Api build command","ignoreCase":"key"},"routes_location":{"type":"string","description":"Routes location","ignoreCase":"key"},"config_file_location":{"type":"string","description":"Config file location","ignoreCase":"key"},"skip_app_build":{"type":"boolean","description":"Skip app build","ignoreCase":"key"},"verbose":{"type":"boolean","description":"Verbose","ignoreCase":"key"},"build_timeout_in_minutes":{"type":"integer","description":"Build timeout in minutes","ignoreCase":"key"},"azure_static_web_apps_api_token":{"type":"string","description":"Azure Static Web Apps api token","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Use Node.js ecosystem\n\nSet up a Node.js environment and add it to the PATH, additionally providing proxy support","ignoreCase":"value","pattern":"^UseNode@1$"},"inputs":{"description":"Use Node.js ecosystem inputs","properties":{"version":{"type":"string","description":"Version","ignoreCase":"key"},"checkLatest":{"type":"boolean","description":"Check for Latest Version","ignoreCase":"key"},"force32bit":{"type":"boolean","description":"Use 32 bit version on x64 agents","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Node.js tool installer\n\nFinds or downloads and caches the specified version spec of Node.js and adds it to the PATH","ignoreCase":"value","pattern":"^NodeTool@0$"},"inputs":{"description":"Node.js tool installer inputs","properties":{"versionSpec":{"type":"string","description":"Version Spec","ignoreCase":"key"},"checkLatest":{"type":"boolean","description":"Check for Latest Version","ignoreCase":"key"},"force32bit":{"type":"boolean","description":"Use 32 bit version on x64 agents","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"UnZip A package\n\nUnZip a package","ignoreCase":"value","pattern":"^unzip@0$"},"inputs":{"description":"UnZip A package inputs","properties":{"pathToZipFile":{"type":"string","description":"Path to the zip file","ignoreCase":"key"},"pathToZipFolder":{"type":"string","description":"Path to folder","ignoreCase":"key"}},"additionalProperties":false,"required":["pathToZipFile","pathToZipFolder"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"[Deprecated] SQL Server database deploy\n\nDeploy a SQL Server database using DACPAC","ignoreCase":"value","pattern":"^SqlServerDacpacDeployment@1$"},"inputs":{"description":"[Deprecated] SQL Server database deploy inputs","properties":{"EnvironmentName":{"type":"string","description":"Machines","ignoreCase":"key"},"AdminUserName":{"type":"string","description":"Admin Login","ignoreCase":"key"},"AdminPassword":{"type":"string","description":"Password","ignoreCase":"key"},"Protocol":{"description":"Protocol","ignoreCase":"all","enum":["Http","Https"]},"TestCertificate":{"type":"boolean","description":"Test Certificate","ignoreCase":"key"},"DacpacFile":{"type":"string","description":"DACPAC File","ignoreCase":"key"},"TargetMethod":{"description":"Specify SQL Using","ignoreCase":"all","enum":["server","connectionString","publishProfile"]},"ServerName":{"type":"string","description":"Server Name","ignoreCase":"key"},"DatabaseName":{"type":"string","description":"Database Name","ignoreCase":"key"},"SqlUsername":{"type":"string","description":"SQL Username","ignoreCase":"key"},"SqlPassword":{"type":"string","description":"SQL Password","ignoreCase":"key"},"ConnectionString":{"type":"string","description":"Connection String","ignoreCase":"key"},"PublishProfile":{"type":"string","description":"Publish Profile","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"},"DeployInParallel":{"type":"boolean","description":"Deploy in Parallel","ignoreCase":"key"},"ResourceFilteringMethod":{"description":"Select Machines By","ignoreCase":"all","enum":["machineNames","tags"]},"MachineFilter":{"type":"string","description":"Deploy to Machines","ignoreCase":"key"}},"additionalProperties":false,"required":["EnvironmentName","DacpacFile"]}},"deprecationMessage":"SqlServerDacpacDeployment is deprecated - Deploy a SQL Server database using DACPAC","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Visual Studio test platform installer\n\nAcquire the test platform from nuget.org or the tool cache. Satisfies the ‘vstest’ demand and can be used for running tests and collecting diagnostic data using the Visual Studio Test task.","ignoreCase":"value","pattern":"^VisualStudioTestPlatformInstaller@1$"},"inputs":{"description":"Visual Studio test platform installer inputs","properties":{"packageFeedSelector":{"description":"Package Feed","ignoreCase":"all","enum":["nugetOrg","customFeed","netShare"]},"versionSelector":{"description":"Version","ignoreCase":"all","enum":["latestPreRelease","latestStable","specificVersion"]},"testPlatformVersion":{"type":"string","description":"Test Platform Version","ignoreCase":"key"},"customFeed":{"type":"string","description":"Package Source","ignoreCase":"key"},"username":{"type":"string","description":"User Name","ignoreCase":"key"},"password":{"type":"string","description":"Password","ignoreCase":"key"},"netShare":{"type":"string","description":"UNC Path","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Publish To Azure Service Bus\n\nSends a message to Azure Service Bus using a service connection (no agent is required)","ignoreCase":"value","pattern":"^PublishToAzureServiceBus@1$"},"inputs":{"description":"Publish To Azure Service Bus inputs","properties":{"azureSubscription":{"type":"string","description":"Azure Service Bus service connection","ignoreCase":"key","aliases":["connectedServiceName"]},"messageBody":{"type":"string","description":"Message body","ignoreCase":"key"},"sessionId":{"type":"string","description":"Session Id","ignoreCase":"key"},"signPayload":{"type":"boolean","description":"Sign the Message","ignoreCase":"key"},"certificateString":{"type":"string","description":"Certificate Variable","ignoreCase":"key"},"signatureKey":{"type":"string","description":"Signature Property Key","ignoreCase":"key"},"waitForCompletion":{"type":"boolean","description":"Wait for task completion","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Publish To Azure Service Bus\n\nSends a message to azure service bus using a service connection (no agent required).","ignoreCase":"value","pattern":"^PublishToAzureServiceBus@0$"},"inputs":{"description":"Publish To Azure Service Bus inputs","properties":{"azureSubscription":{"type":"string","description":"Azure service bus connection","ignoreCase":"key","aliases":["connectedServiceName"]},"messageBody":{"type":"string","description":"Message body","ignoreCase":"key"},"waitForCompletion":{"type":"boolean","description":"Wait for task completion","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Deploy to Kubernetes\n\nUse Kubernetes manifest files to deploy to clusters or even bake the manifest files to be used for deployments using Helm charts","ignoreCase":"value","pattern":"^KubernetesManifest@0$"},"inputs":{"description":"Deploy to Kubernetes inputs","properties":{"action":{"description":"Action","ignoreCase":"all","enum":["bake","createSecret","delete","deploy","patch","promote","scale","reject"]},"kubernetesServiceConnection":{"type":"string","description":"Kubernetes service connection","ignoreCase":"key"},"namespace":{"type":"string","description":"Namespace","ignoreCase":"key"},"strategy":{"description":"Strategy","ignoreCase":"all","enum":["canary","none"]},"trafficSplitMethod":{"description":"Traffic split method","ignoreCase":"all","enum":["pod","smi"]},"percentage":{"type":"string","description":"Percentage","ignoreCase":"key"},"baselineAndCanaryReplicas":{"type":"string","description":"Baseline and canary replicas","ignoreCase":"key"},"manifests":{"type":"string","description":"Manifests","ignoreCase":"key"},"containers":{"type":"string","description":"Containers","ignoreCase":"key"},"imagePullSecrets":{"type":"string","description":"ImagePullSecrets","ignoreCase":"key"},"renderType":{"description":"Render Engine","ignoreCase":"all","enum":["helm","kompose","kustomize"]},"dockerComposeFile":{"type":"string","description":"Path to docker compose file","ignoreCase":"key"},"helmChart":{"type":"string","description":"Helm Chart","ignoreCase":"key"},"releaseName":{"type":"string","description":"Helm Release Name","ignoreCase":"key"},"overrideFiles":{"type":"string","description":"Override Files","ignoreCase":"key"},"overrides":{"type":"string","description":"Overrides","ignoreCase":"key"},"kustomizationPath":{"type":"string","description":"Kustomization Path","ignoreCase":"key"},"resourceToPatch":{"description":"Resource to patch","ignoreCase":"all","enum":["file","name"]},"resourceFileToPatch":{"type":"string","description":"File path","ignoreCase":"key"},"kind":{"description":"Kind","ignoreCase":"all","enum":["deployment","replicaset","statefulset"]},"name":{"type":"string","description":"Name","ignoreCase":"key"},"replicas":{"type":"string","description":"Replica count","ignoreCase":"key"},"mergeStrategy":{"description":"Merge Strategy","ignoreCase":"all","enum":["json","merge","strategic"]},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"patch":{"type":"string","description":"Patch","ignoreCase":"key"},"secretType":{"description":"Type of secret","ignoreCase":"all","enum":["dockerRegistry","generic"]},"secretName":{"type":"string","description":"Secret name","ignoreCase":"key"},"secretArguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"dockerRegistryEndpoint":{"type":"string","description":"Docker registry service connection","ignoreCase":"key"},"rolloutStatusTimeout":{"type":"string","description":"Timeout for rollout status","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Download build artifacts\n\nDownload files that were saved as artifacts of a completed build","ignoreCase":"value","pattern":"^DownloadBuildArtifacts@1$"},"inputs":{"description":"Download build artifacts inputs","properties":{"buildType":{"description":"Download artifacts produced by","ignoreCase":"all","enum":["current","specific"]},"project":{"type":"string","description":"Project","ignoreCase":"key"},"pipeline":{"type":"string","description":"Build pipeline","ignoreCase":"key","aliases":["definition"]},"specificBuildWithTriggering":{"type":"boolean","description":"When appropriate, download artifacts from the triggering build.","ignoreCase":"key"},"buildVersionToDownload":{"description":"Build version to download","ignoreCase":"all","enum":["latest","latestFromBranch","specific"]},"allowPartiallySucceededBuilds":{"type":"boolean","description":"Download artifacts even from partially succeeded builds.","ignoreCase":"key"},"branchName":{"type":"string","description":"Branch name","ignoreCase":"key"},"buildId":{"type":"string","description":"Build","ignoreCase":"key"},"tags":{"type":"string","description":"Build Tags","ignoreCase":"key"},"downloadType":{"description":"Download type","ignoreCase":"all","enum":["single","specific"]},"artifactName":{"type":"string","description":"Artifact name","ignoreCase":"key"},"itemPattern":{"type":"string","description":"Matching pattern","ignoreCase":"key"},"downloadPath":{"type":"string","description":"Destination directory","ignoreCase":"key"},"parallelizationLimit":{"type":"string","description":"Parallelization limit","ignoreCase":"key"},"checkDownloadedFiles":{"type":"boolean","description":"Check downloaded files","ignoreCase":"key"},"retryDownloadCount":{"type":"string","description":"Retry count","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Download build artifacts\n\nDownload files that were saved as artifacts of a completed build","ignoreCase":"value","pattern":"^DownloadBuildArtifacts@0$"},"inputs":{"description":"Download build artifacts inputs","properties":{"buildType":{"description":"Download artifacts produced by","ignoreCase":"all","enum":["current","specific"]},"project":{"type":"string","description":"Project","ignoreCase":"key"},"pipeline":{"type":"string","description":"Build pipeline","ignoreCase":"key","aliases":["definition"]},"specificBuildWithTriggering":{"type":"boolean","description":"When appropriate, download artifacts from the triggering build.","ignoreCase":"key"},"buildVersionToDownload":{"description":"Build version to download","ignoreCase":"all","enum":["latest","latestFromBranch","specific"]},"allowPartiallySucceededBuilds":{"type":"boolean","description":"Download artifacts even from partially succeeded builds.","ignoreCase":"key"},"branchName":{"type":"string","description":"Branch name","ignoreCase":"key"},"buildId":{"type":"string","description":"Build","ignoreCase":"key"},"tags":{"type":"string","description":"Build Tags","ignoreCase":"key"},"downloadType":{"description":"Download type","ignoreCase":"all","enum":["single","specific"]},"artifactName":{"type":"string","description":"Artifact name","ignoreCase":"key"},"itemPattern":{"type":"string","description":"Matching pattern","ignoreCase":"key"},"downloadPath":{"type":"string","description":"Destination directory","ignoreCase":"key"},"cleanDestinationFolder":{"type":"boolean","description":"Clean destination folder","ignoreCase":"key"},"parallelizationLimit":{"type":"string","description":"Parallelization limit","ignoreCase":"key"},"checkDownloadedFiles":{"type":"boolean","description":"Check downloaded files","ignoreCase":"key"},"retryDownloadCount":{"type":"string","description":"Retry count","ignoreCase":"key"},"extractTars":{"type":"boolean","description":"Extract all files that are stored inside tar archives","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"CocoaPods\n\nInstall CocoaPods dependencies for Swift and Objective-C Cocoa projects","ignoreCase":"value","pattern":"^CocoaPods@0$"},"inputs":{"description":"CocoaPods inputs","properties":{"workingDirectory":{"type":"string","description":"Working directory","ignoreCase":"key","aliases":["cwd"]},"forceRepoUpdate":{"type":"boolean","description":"Force repo update","ignoreCase":"key"},"projectDirectory":{"type":"string","description":"Project directory","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Archive Symbols\n\nArchives symbols on Symweb.","ignoreCase":"value","pattern":"^MicroBuildArchiveSymbols@1$"},"inputs":{"description":"MicroBuild Archive Symbols inputs","properties":{"SymbolsFeatureName":{"type":"string","description":"Feature Name","ignoreCase":"key"},"SymbolsSymwebProject":{"description":"Symweb Project","ignoreCase":"all","enum":["VS","CLR","DDE"]},"SymbolsUncPath":{"type":"string","description":"UNC Path to Symbols","ignoreCase":"key"},"SymbolsEmailContacts":{"type":"string","description":"Team Contacts","ignoreCase":"key"},"SubmitToInternet":{"type":"boolean","description":"Submit to Internet","ignoreCase":"key"},"CreateBuildArtifact":{"type":"boolean","description":"Create Build Artifact","ignoreCase":"key"},"SymbolsAgentPath":{"type":"string","description":"Agent Path to Symbols","ignoreCase":"key"},"ExcludeAgentFolders":{"type":"string","description":"Exclude Agent Folders","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure Spring Cloud\n\nDeploy applications to Azure Spring Cloud and manage deployments.","ignoreCase":"value","pattern":"^AzureSpringCloud@0$"},"inputs":{"description":"Azure Spring Cloud inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"Action":{"description":"Action","ignoreCase":"all","enum":["Deploy","Set Production","Delete Staging Deployment"]},"AzureSpringCloud":{"type":"string","description":"Azure Spring Cloud Name","ignoreCase":"key"},"AppName":{"type":"string","description":"App","ignoreCase":"key"},"UseStagingDeployment":{"type":"boolean","description":"Use Staging Deployment","ignoreCase":"key"},"CreateNewDeployment":{"type":"boolean","description":"Create a new staging deployment if one does not exist.","ignoreCase":"key"},"DeploymentName":{"type":"string","description":"Deployment","ignoreCase":"key"},"Package":{"type":"string","description":"Package or folder","ignoreCase":"key"},"EnvironmentVariables":{"type":"string","description":"Environment Variables","ignoreCase":"key"},"JvmOptions":{"type":"string","description":"JVM Options","ignoreCase":"key"},"RuntimeVersion":{"description":"Runtime Version","ignoreCase":"all","enum":["Java_8","Java_11","NetCore_31"]},"DotNetCoreMainEntryPath":{"type":"string","description":"Main Entry Path","ignoreCase":"key"},"Version":{"type":"string","description":"Version","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","AzureSpringCloud","AppName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure Web App\n\nDeploy an Azure Web App for Linux or Windows","ignoreCase":"value","pattern":"^AzureWebApp@1$"},"inputs":{"description":"Azure Web App inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key"},"appType":{"description":"App type","ignoreCase":"all","enum":["webApp","webAppLinux"]},"appName":{"type":"string","description":"App name","ignoreCase":"key"},"deployToSlotOrASE":{"type":"boolean","description":"Deploy to Slot or App Service Environment","ignoreCase":"key"},"resourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"slotName":{"type":"string","description":"Slot","ignoreCase":"key"},"package":{"type":"string","description":"Package or folder","ignoreCase":"key"},"customDeployFolder":{"type":"string","description":"Custom Deploy Folder","ignoreCase":"key"},"runtimeStack":{"type":"string","description":"Runtime stack","ignoreCase":"key"},"startUpCommand":{"type":"string","description":"Startup command ","ignoreCase":"key"},"customWebConfig":{"type":"string","description":"Generate web.config parameters for Python, Node.js, Go and Java apps","ignoreCase":"key"},"appSettings":{"type":"string","description":"App settings","ignoreCase":"key"},"configurationStrings":{"type":"string","description":"Configuration settings","ignoreCase":"key"},"deploymentMethod":{"description":"Deployment method","ignoreCase":"all","enum":["auto","zipDeploy","runFromPackage"]}},"additionalProperties":false,"required":["azureSubscription","appType","appName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure CLI\n\nRun Azure CLI commands against an Azure subscription in a Shell script when running on Linux agent or Batch script when running on Windows agent.","ignoreCase":"value","pattern":"^AzureCLI@1$"},"inputs":{"description":"Azure CLI inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["connectedServiceNameARM"]},"scriptLocation":{"description":"Script Location","ignoreCase":"all","enum":["inlineScript","scriptPath"]},"scriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"inlineScript":{"type":"string","description":"Inline Script","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key","aliases":["args"]},"addSpnToEnvironment":{"type":"boolean","description":"Access service principal details in script","ignoreCase":"key"},"useGlobalConfig":{"type":"boolean","description":"Use global Azure CLI configuration","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["cwd"]},"failOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure CLI\n\nRun Azure CLI commands against an Azure subscription in a PowerShell Core/Shell script when running on Linux agent or PowerShell/PowerShell Core/Batch script when running on Windows agent.","ignoreCase":"value","pattern":"^AzureCLI@2$"},"inputs":{"description":"Azure CLI inputs","properties":{"azureSubscription":{"type":"string","description":"Azure Resource Manager connection","ignoreCase":"key","aliases":["connectedServiceNameARM"]},"scriptType":{"description":"Script Type","ignoreCase":"all","enum":["ps","pscore","batch","bash"]},"scriptLocation":{"description":"Script Location","ignoreCase":"all","enum":["inlineScript","scriptPath"]},"scriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"inlineScript":{"type":"string","description":"Inline Script","ignoreCase":"key"},"arguments":{"type":"string","description":"Script Arguments","ignoreCase":"key","aliases":["scriptArguments"]},"powerShellErrorActionPreference":{"description":"ErrorActionPreference","ignoreCase":"all","enum":["stop","continue","silentlyContinue"]},"addSpnToEnvironment":{"type":"boolean","description":"Access service principal details in script","ignoreCase":"key"},"useGlobalConfig":{"type":"boolean","description":"Use global Azure CLI configuration","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["cwd"]},"failOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"},"powerShellIgnoreLASTEXITCODE":{"type":"boolean","description":"Ignore $LASTEXITCODE","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","scriptType"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure CLI Preview\n\nRun a Shell or Batch script with Azure CLI commands against an azure subscription","ignoreCase":"value","pattern":"^AzureCLI@0$"},"inputs":{"description":"Azure CLI Preview inputs","properties":{"connectedServiceNameSelector":{"description":"Azure Connection Type","ignoreCase":"all","enum":["connectedServiceName","connectedServiceNameARM"]},"connectedServiceNameARM":{"type":"string","description":"AzureRM Subscription","ignoreCase":"key"},"connectedServiceName":{"type":"string","description":"Azure Classic Subscription","ignoreCase":"key"},"scriptLocation":{"description":"Script Location","ignoreCase":"all","enum":["inlineScript","scriptPath"]},"scriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"inlineScript":{"type":"string","description":"Inline Script","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"cwd":{"type":"string","description":"Working Directory","ignoreCase":"key"},"failOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild VC Error Codes Plugin\n\nInstalls and configures the MicroBuild VC Error Codes plugin for use during the build","ignoreCase":"value","pattern":"^MicroBuildVCErrorCodesPlugin@2$"},"inputs":{"description":"MicroBuild VC Error Codes Plugin inputs","properties":{"version":{"type":"string","description":"Plugin Version Override","ignoreCase":"key"},"feedSource":{"type":"string","description":"NuGet feed location where the plugin is located","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Azure Cosmos DB Emulator\n\nCreate and start an Azure Cosmos DB Emulator container for testing","ignoreCase":"value","pattern":"^CosmosDbEmulator@2$"},"inputs":{"description":"Azure Cosmos DB Emulator inputs","properties":{"containerName":{"type":"string","description":"Container Name","ignoreCase":"key"},"enableAPI":{"type":"string","description":"API","ignoreCase":"key"},"portMapping":{"type":"string","description":"Port mapping","ignoreCase":"key"},"hostDirectory":{"type":"string","description":"Host Directory","ignoreCase":"key"},"consistency":{"description":"Consistency Level","ignoreCase":"all","enum":["BoundedStaleness","Eventual","Session","Strong"]},"partitionCount":{"type":"string","description":"Number of 10GB data partitions to allocate","ignoreCase":"key"},"defaultPartitionCount":{"type":"string","description":"Number of 10GB partitions to reserve per partitioned collection","ignoreCase":"key"},"simulateRateLimiting":{"type":"boolean","description":"Simulate Rate Limiting","ignoreCase":"key"},"trace":{"type":"boolean","description":"Enable Tracing","ignoreCase":"key"},"startingTimeout":{"type":"string","description":"Emulator Start Timeout","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Codesign Verification\n\nVerifies that files have been correctly codesigned","ignoreCase":"value","pattern":"^MicroBuildCodesignVerify@2$"},"inputs":{"description":"MicroBuild Codesign Verification inputs","properties":{"TargetFolders":{"type":"string","description":"Folders to Verify","ignoreCase":"key"},"WhiteListPathForCerts":{"type":"string","description":"Location of WhiteList File for Authenticode Certificates","ignoreCase":"key"},"WhiteListPathForSigs":{"type":"string","description":"Location of WhiteList File for Strong Name Signatures","ignoreCase":"key"},"ExcludeSNVerify":{"type":"boolean","description":"Exclude Strong Name Verification","ignoreCase":"key"},"ExcludeFolders":{"type":"string","description":"Folders to Exclude","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"MicroBuild Codesign Verification\n\nVerifies that files have been correctly codesigned","ignoreCase":"value","pattern":"^MicroBuildCodesignVerify@3$"},"inputs":{"description":"MicroBuild Codesign Verification inputs","properties":{"TargetFolders":{"type":"string","description":"Folders to Verify","ignoreCase":"key"},"ApprovalListPathForCerts":{"type":"string","description":"Location of approval list File for Authenticode Certificates","ignoreCase":"key"},"ApprovalListPathForSigs":{"type":"string","description":"Location of approval list File for Strong Name Signatures","ignoreCase":"key"},"ExcludeSNVerify":{"type":"boolean","description":"Exclude Strong Name Verification","ignoreCase":"key"},"ExcludeFolders":{"type":"string","description":"Folders to Exclude","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"GitHub Release\n\nCreate, edit, or delete a GitHub release","ignoreCase":"value","pattern":"^GitHubRelease@1$"},"inputs":{"description":"GitHub Release inputs","properties":{"gitHubConnection":{"type":"string","description":"GitHub connection (OAuth or PAT)","ignoreCase":"key"},"repositoryName":{"type":"string","description":"Repository","ignoreCase":"key"},"action":{"description":"Action","ignoreCase":"all","enum":["create","edit","delete"]},"target":{"type":"string","description":"Target","ignoreCase":"key"},"tagSource":{"description":"Tag source","ignoreCase":"all","enum":["gitTag","userSpecifiedTag"]},"tagPattern":{"type":"string","description":"Tag Pattern","ignoreCase":"key"},"tag":{"type":"string","description":"Tag","ignoreCase":"key"},"title":{"type":"string","description":"Release title","ignoreCase":"key"},"releaseNotesSource":{"description":"Release notes source","ignoreCase":"all","enum":["filePath","inline"]},"releaseNotesFilePath":{"type":"string","description":"Release notes file path","ignoreCase":"key"},"releaseNotesInline":{"type":"string","description":"Release notes","ignoreCase":"key"},"assets":{"type":"string","description":"Assets","ignoreCase":"key"},"assetUploadMode":{"description":"Asset upload mode","ignoreCase":"all","enum":["delete","replace"]},"isDraft":{"type":"boolean","description":"Draft release","ignoreCase":"key"},"isPreRelease":{"type":"boolean","description":"Pre-release","ignoreCase":"key"},"addChangeLog":{"type":"boolean","description":"Add changelog","ignoreCase":"key"},"changeLogCompareToRelease":{"description":"Compare to","ignoreCase":"all","enum":["lastFullRelease","lastNonDraftRelease","lastNonDraftReleaseByTag"]},"changeLogCompareToReleaseTag":{"type":"string","description":"Release Tag","ignoreCase":"key"},"changeLogType":{"description":"Changelog type","ignoreCase":"all","enum":["commitBased","issueBased"]},"changeLogLabels":{"type":"string","description":"Categories","ignoreCase":"key"}},"additionalProperties":false,"required":["gitHubConnection"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"GitHub Release\n\nCreate, edit, or delete a GitHub release","ignoreCase":"value","pattern":"^GitHubRelease@0$"},"inputs":{"description":"GitHub Release inputs","properties":{"gitHubConnection":{"type":"string","description":"GitHub connection (OAuth or PAT)","ignoreCase":"key"},"repositoryName":{"type":"string","description":"Repository","ignoreCase":"key"},"action":{"description":"Action","ignoreCase":"all","enum":["create","edit","delete"]},"target":{"type":"string","description":"Target","ignoreCase":"key"},"tagSource":{"description":"Tag source","ignoreCase":"all","enum":["auto","manual"]},"tagPattern":{"type":"string","description":"Tag Pattern","ignoreCase":"key"},"tag":{"type":"string","description":"Tag","ignoreCase":"key"},"title":{"type":"string","description":"Release title","ignoreCase":"key"},"releaseNotesSource":{"description":"Release notes source","ignoreCase":"all","enum":["file","input"]},"releaseNotesFile":{"type":"string","description":"Release notes file path","ignoreCase":"key"},"releaseNotes":{"type":"string","description":"Release notes","ignoreCase":"key"},"assets":{"type":"string","description":"Assets","ignoreCase":"key"},"assetUploadMode":{"description":"Asset upload mode","ignoreCase":"all","enum":["delete","replace"]},"isDraft":{"type":"boolean","description":"Draft release","ignoreCase":"key"},"isPreRelease":{"type":"boolean","description":"Pre-release","ignoreCase":"key"},"addChangeLog":{"type":"boolean","description":"Add changelog","ignoreCase":"key"},"changeLogCompareToRelease":{"description":"Compare to","ignoreCase":"all","enum":["lastFullRelease","lastNonDraftRelease","lastNonDraftReleaseByTag"]},"changeLogCompareToReleaseTag":{"type":"string","description":"Release Tag","ignoreCase":"key"},"changeLogType":{"description":"Changelog type","ignoreCase":"all","enum":["commitBased","issueBased"]},"changeLogLabels":{"type":"string","description":"Categories","ignoreCase":"key"}},"additionalProperties":false,"required":["gitHubConnection"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"cURL Upload Files\n\nUse cURL to upload files with FTP, FTPS, SFTP, HTTP, and more.","ignoreCase":"value","pattern":"^cURLUploader@1$"},"inputs":{"description":"cURL Upload Files inputs","properties":{"files":{"type":"string","description":"Files","ignoreCase":"key"},"username":{"type":"string","description":"Username","ignoreCase":"key"},"password":{"type":"string","description":"Password","ignoreCase":"key"},"url":{"type":"string","description":"URL","ignoreCase":"key"},"options":{"type":"string","description":"Optional Arguments","ignoreCase":"key"},"redirectStderr":{"type":"boolean","description":"Redirect Standard Error to Standard Out","ignoreCase":"key"}},"additionalProperties":false,"required":["files","url"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"cURL upload files\n\nUse cURL's supported protocols to upload files","ignoreCase":"value","pattern":"^cURLUploader@2$"},"inputs":{"description":"cURL upload files inputs","properties":{"files":{"type":"string","description":"Files","ignoreCase":"key"},"authType":{"description":"Authentication Method","ignoreCase":"all","enum":["ServiceEndpoint","UserAndPass"]},"serviceEndpoint":{"type":"string","description":"Service Connection","ignoreCase":"key"},"username":{"type":"string","description":"Username","ignoreCase":"key"},"password":{"type":"string","description":"Password","ignoreCase":"key"},"url":{"type":"string","description":"URL","ignoreCase":"key"},"remotePath":{"type":"string","description":"Remote Directory","ignoreCase":"key"},"options":{"type":"string","description":"Optional Arguments","ignoreCase":"key"},"redirectStderr":{"type":"boolean","description":"Redirect Standard Error to Standard Out","ignoreCase":"key"}},"additionalProperties":false,"required":["files"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure App Service Settings\n\nUpdate/Add App settings an Azure Web App for Linux or Windows","ignoreCase":"value","pattern":"^AzureAppServiceSettings@1$"},"inputs":{"description":"Azure App Service Settings inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"appName":{"type":"string","description":"App Service name","ignoreCase":"key"},"resourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"slotName":{"type":"string","description":"Slot","ignoreCase":"key"},"appSettings":{"type":"string","description":"App settings","ignoreCase":"key"},"generalSettings":{"type":"string","description":"General settings","ignoreCase":"key"},"connectionStrings":{"type":"string","description":"Connection Strings","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","appName","resourceGroupName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Universal packages\n\nDownload or publish Universal Packages","ignoreCase":"value","pattern":"^UniversalPackages@0$"},"inputs":{"description":"Universal packages inputs","properties":{"command":{"description":"Command","ignoreCase":"all","enum":["download","publish"]},"downloadDirectory":{"type":"string","description":"Destination directory","ignoreCase":"key","aliases":["downloadDirectory"]},"feedsToUse":{"description":"Feed location","ignoreCase":"all","enum":["internal","external"],"aliases":["internalOrExternalDownload"]},"externalFeedCredentials":{"type":"string","description":"organization/collection connection","ignoreCase":"key","aliases":["externalEndpoint"]},"vstsFeed":{"type":"string","description":"Feed","ignoreCase":"key","aliases":["feedListDownload"]},"vstsFeedPackage":{"type":"string","description":"Package name","ignoreCase":"key","aliases":["packageListDownload"]},"vstsPackageVersion":{"type":"string","description":"Version","ignoreCase":"key","aliases":["versionListDownload"]},"feedDownloadExternal":{"type":"string","description":"Feed (or Project/Feed if the feed was created in a project)","ignoreCase":"key"},"packageDownloadExternal":{"type":"string","description":"Package name","ignoreCase":"key"},"versionDownloadExternal":{"type":"string","description":"Version","ignoreCase":"key"},"publishDirectory":{"type":"string","description":"Path to file(s) to publish","ignoreCase":"key","aliases":["publishDirectory"]},"feedsToUsePublish":{"description":"Feed location","ignoreCase":"all","enum":["internal","external"],"aliases":["internalOrExternalPublish"]},"publishFeedCredentials":{"type":"string","description":"organization/collection connection","ignoreCase":"key","aliases":["externalEndpoints"]},"vstsFeedPublish":{"type":"string","description":"Destination Feed","ignoreCase":"key","aliases":["feedListPublish"]},"publishPackageMetadata":{"type":"boolean","description":"Publish pipeline metadata","ignoreCase":"key"},"vstsFeedPackagePublish":{"type":"string","description":"Package name","ignoreCase":"key","aliases":["packageListPublish"]},"feedPublishExternal":{"type":"string","description":"Feed (or Project/Feed if the feed was created in a project)","ignoreCase":"key"},"packagePublishExternal":{"type":"string","description":"Package name","ignoreCase":"key"},"versionOption":{"description":"Version","ignoreCase":"all","enum":["major","minor","patch","custom"],"aliases":["versionPublishSelector"]},"versionPublish":{"type":"string","description":"Custom version","ignoreCase":"key"},"packagePublishDescription":{"type":"string","description":"Description","ignoreCase":"key"},"verbosity":{"description":"Verbosity","ignoreCase":"all","enum":["None","Trace","Debug","Information","Warning","Error","Critical"]},"publishedPackageVar":{"type":"string","description":"Package Output Variable","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Check Azure Policy compliance\n\nSecurity and compliance assessment for Azure Policy","ignoreCase":"value","pattern":"^AzurePolicyCheckGate@0$"},"inputs":{"description":"Check Azure Policy compliance inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"ResourceGroupName":{"type":"string","description":"Resource group","ignoreCase":"key"},"Resources":{"type":"string","description":"Resource name","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure Function on Kubernetes\n\nDeploy Azure function to Kubernetes cluster.","ignoreCase":"value","pattern":"^AzureFunctionOnKubernetes@0$"},"inputs":{"description":"Azure Function on Kubernetes inputs","properties":{"dockerRegistryServiceConnection":{"type":"string","description":"Docker registry service connection","ignoreCase":"key"},"kubernetesServiceConnection":{"type":"string","description":"Kubernetes service connection","ignoreCase":"key"},"namespace":{"type":"string","description":"Kubernetes namespace","ignoreCase":"key"},"secretName":{"type":"string","description":"Secret Name","ignoreCase":"key"},"dockerHubNamespace":{"type":"string","description":"Docker Hub namespace","ignoreCase":"key"},"appName":{"type":"string","description":"Application Name","ignoreCase":"key"},"functionRootDirectory":{"type":"string","description":"Function root directory","ignoreCase":"key"},"waitForStability":{"type":"boolean","description":"Wait for stability","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":["dockerRegistryServiceConnection","kubernetesServiceConnection","appName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"MicroBuild Retain Azure DevOps Drops\n\nRetains one or more Azure DevOps Drops permanently","ignoreCase":"value","pattern":"^MicroBuildRetainVstsDrops@1$"},"inputs":{"description":"MicroBuild Retain Azure DevOps Drops inputs","properties":{"DropNames":{"type":"string","description":"Drop Names","ignoreCase":"key"},"AccessToken":{"type":"string","description":"Drop Service Access Token","ignoreCase":"key"},"DropServiceUri":{"type":"string","description":"Drop Service Uri","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Shell script\n\nRun a shell script using Bash","ignoreCase":"value","pattern":"^ShellScript@2$"},"inputs":{"description":"Shell script inputs","properties":{"scriptPath":{"type":"string","description":"Script Path","ignoreCase":"key"},"args":{"type":"string","description":"Arguments","ignoreCase":"key"},"disableAutoCwd":{"type":"boolean","description":"Specify Working Directory","ignoreCase":"key"},"cwd":{"type":"string","description":"Working Directory","ignoreCase":"key"},"failOnStandardError":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"}},"additionalProperties":false,"required":["scriptPath"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Bash\n\nRun a Bash script on macOS, Linux, or Windows","ignoreCase":"value","pattern":"^Bash@3$"},"inputs":{"description":"Bash inputs","properties":{"targetType":{"description":"Type","ignoreCase":"all","enum":["filePath","inline"]},"filePath":{"type":"string","description":"Script Path","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"script":{"type":"string","description":"Script","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key"},"failOnStderr":{"type":"boolean","description":"Fail on Standard Error","ignoreCase":"key"},"bashEnvValue":{"type":"string","description":"Set value for BASH_ENV environment variable","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Publish build artifacts\n\nPublish build artifacts to Azure Pipelines or a Windows file share","ignoreCase":"value","pattern":"^PublishBuildArtifacts@1$"},"inputs":{"description":"Publish build artifacts inputs","properties":{"PathtoPublish":{"type":"string","description":"Path to publish","ignoreCase":"key"},"ArtifactName":{"type":"string","description":"Artifact name","ignoreCase":"key"},"publishLocation":{"description":"Artifact publish location","ignoreCase":"all","enum":["Container","FilePath"],"aliases":["ArtifactType"]},"TargetPath":{"type":"string","description":"File share path","ignoreCase":"key"},"Parallel":{"type":"boolean","description":"Parallel copy","ignoreCase":"key"},"ParallelCount":{"type":"integer","description":"Parallel count","ignoreCase":"key"},"FileCopyOptions":{"type":"string","description":"File copy options","ignoreCase":"key"},"StoreAsTar":{"type":"boolean","description":"Tar the artifact before uploading","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Install SSH key\n\nInstall an SSH key prior to a build or deployment","ignoreCase":"value","pattern":"^InstallSSHKey@0$"},"inputs":{"description":"Install SSH key inputs","properties":{"knownHostsEntry":{"type":"string","description":"Known Hosts Entry","ignoreCase":"key","aliases":["hostName"]},"sshPublicKey":{"type":"string","description":"SSH Public Key","ignoreCase":"key"},"sshPassphrase":{"type":"string","description":"SSH Passphrase","ignoreCase":"key"},"sshKeySecureFile":{"type":"string","description":"SSH Key","ignoreCase":"key"},"addEntryToConfig":{"type":"boolean","description":"Add entry to SSH config","ignoreCase":"key"},"configHostAlias":{"type":"string","description":"Alias","ignoreCase":"key"},"configHostname":{"type":"string","description":"Host name","ignoreCase":"key"},"configUser":{"type":"string","description":"User","ignoreCase":"key"},"configPort":{"type":"string","description":"Port","ignoreCase":"key"}},"additionalProperties":false,"required":["knownHostsEntry","sshKeySecureFile"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure VM scale set deployment\n\nDeploy a virtual machine scale set image","ignoreCase":"value","pattern":"^AzureVmssDeployment@0$"},"inputs":{"description":"Azure VM scale set deployment inputs","properties":{"azureSubscription":{"type":"string","description":"Azure subscription","ignoreCase":"key","aliases":["ConnectedServiceName"]},"action":{"description":"Action","ignoreCase":"all","enum":["Update image","Configure application startup"]},"vmssName":{"type":"string","description":"Virtual Machine scale set name","ignoreCase":"key"},"vmssOsType":{"description":"OS type","ignoreCase":"all","enum":["Windows","Linux"]},"imageUrl":{"type":"string","description":"Image URL","ignoreCase":"key"},"customScriptsDirectory":{"type":"string","description":"Custom script directory","ignoreCase":"key"},"customScript":{"type":"string","description":"Command","ignoreCase":"key"},"customScriptArguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"customScriptsStorageAccount":{"type":"string","description":"Azure storage account where custom scripts will be uploaded","ignoreCase":"key"},"skipArchivingCustomScripts":{"type":"boolean","description":"Skip Archiving custom scripts","ignoreCase":"key"}},"additionalProperties":false,"required":["azureSubscription","vmssName","vmssOsType","imageUrl"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Tag Build or Release\n\nAdds tags to a build or release","ignoreCase":"value","pattern":"^tagBuildOrRelease@0$"},"inputs":{"description":"Tag Build or Release inputs","properties":{"type":{"description":"Type","ignoreCase":"all","enum":["Build","Release"]},"tags":{"type":"string","description":"Tags","ignoreCase":"key"}},"additionalProperties":false,"required":["tags"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure App Service: Classic (Deprecated)\n\nCreate or update Azure App Service using Azure PowerShell","ignoreCase":"value","pattern":"^AzureWebPowerShellDeployment@1$"},"inputs":{"description":"Azure App Service: Classic (Deprecated) inputs","properties":{"ConnectedServiceName":{"type":"string","description":"Azure Subscription (Classic)","ignoreCase":"key"},"WebSiteLocation":{"type":"string","description":"Web App Location","ignoreCase":"key"},"WebSiteName":{"type":"string","description":"Web App Name","ignoreCase":"key"},"Slot":{"type":"string","description":"Slot","ignoreCase":"key"},"Package":{"type":"string","description":"Web Deploy Package","ignoreCase":"key"},"doNotDelete":{"type":"boolean","description":"Set DoNotDelete flag","ignoreCase":"key"},"AdditionalArguments":{"type":"string","description":"Additional Arguments","ignoreCase":"key"}},"additionalProperties":false,"required":["ConnectedServiceName","WebSiteLocation","WebSiteName","Package"]}},"deprecationMessage":"AzureWebPowerShellDeployment is deprecated - Create or update Azure App Service using Azure PowerShell","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Azure Cloud Service deployment\n\nDeploy an Azure Cloud Service","ignoreCase":"value","pattern":"^AzureCloudPowerShellDeployment@1$"},"inputs":{"description":"Azure Cloud Service deployment inputs","properties":{"azureClassicSubscription":{"type":"string","description":"Azure subscription (Classic)","ignoreCase":"key","aliases":["ConnectedServiceName"]},"EnableAdvancedStorageOptions":{"type":"boolean","description":"Enable ARM storage support","ignoreCase":"key"},"StorageAccount":{"type":"string","description":"Storage account (Classic)","ignoreCase":"key"},"ARMConnectedServiceName":{"type":"string","description":"Azure subscription (ARM)","ignoreCase":"key"},"ARMStorageAccount":{"type":"string","description":"Storage account (ARM)","ignoreCase":"key"},"ServiceName":{"type":"string","description":"Service name","ignoreCase":"key"},"ServiceLocation":{"type":"string","description":"Service location","ignoreCase":"key"},"CsPkg":{"type":"string","description":"CsPkg","ignoreCase":"key"},"CsCfg":{"type":"string","description":"CsCfg","ignoreCase":"key"},"slotName":{"type":"string","description":"Environment (Slot)","ignoreCase":"key","aliases":["Slot"]},"DeploymentLabel":{"type":"string","description":"Deployment label","ignoreCase":"key"},"AppendDateTimeToLabel":{"type":"boolean","description":"Append current date and time","ignoreCase":"key"},"AllowUpgrade":{"type":"boolean","description":"Allow upgrade","ignoreCase":"key"},"SimultaneousUpgrade":{"type":"boolean","description":"Simultaneous upgrade","ignoreCase":"key"},"ForceUpgrade":{"type":"boolean","description":"Force upgrade","ignoreCase":"key"},"VerifyRoleInstanceStatus":{"type":"boolean","description":"Verify role instance status","ignoreCase":"key"},"DiagnosticStorageAccountKeys":{"type":"string","description":"Diagnostic storage account keys","ignoreCase":"key"},"NewServiceCustomCertificates":{"type":"string","description":"Custom certificates to import","ignoreCase":"key"},"NewServiceAdditionalArguments":{"type":"string","description":"Additional arguments","ignoreCase":"key"},"NewServiceAffinityGroup":{"type":"string","description":"Affinity group","ignoreCase":"key"}},"additionalProperties":false,"required":["azureClassicSubscription","ServiceName","ServiceLocation","CsPkg","CsCfg"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Delete files\n\nDelete folders, or files matching a pattern","ignoreCase":"value","pattern":"^DeleteFiles@1$"},"inputs":{"description":"Delete files inputs","properties":{"SourceFolder":{"type":"string","description":"Source Folder","ignoreCase":"key"},"Contents":{"type":"string","description":"Contents","ignoreCase":"key"},"RemoveSourceFolder":{"type":"boolean","description":"Remove SourceFolder","ignoreCase":"key"},"RemoveDotFiles":{"type":"boolean","description":"Remove files starting with a dot","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"gulp\n\nRun the gulp Node.js streaming task-based build system","ignoreCase":"value","pattern":"^gulp@1$"},"inputs":{"description":"gulp inputs","properties":{"gulpFile":{"type":"string","description":"gulp File Path","ignoreCase":"key"},"targets":{"type":"string","description":"gulp Task(s)","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["cwd"]},"gulpjs":{"type":"string","description":"gulp.js location","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to Azure Pipelines","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test Results Files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test Run Title","ignoreCase":"key"},"enableCodeCoverage":{"type":"boolean","description":"Enable code Coverage","ignoreCase":"key"},"testFramework":{"description":"Test Framework","ignoreCase":"all","enum":["Mocha","Jasmine"]},"srcFiles":{"type":"string","description":"Source Files","ignoreCase":"key"},"testFiles":{"type":"string","description":"Test Script Files","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"gulp\n\nRun the gulp Node.js streaming task-based build system","ignoreCase":"value","pattern":"^gulp@0$"},"inputs":{"description":"gulp inputs","properties":{"gulpFile":{"type":"string","description":"gulp File Path","ignoreCase":"key"},"targets":{"type":"string","description":"gulp Task(s)","ignoreCase":"key"},"arguments":{"type":"string","description":"Arguments","ignoreCase":"key"},"workingDirectory":{"type":"string","description":"Working Directory","ignoreCase":"key","aliases":["cwd"]},"gulpjs":{"type":"string","description":"gulp.js location","ignoreCase":"key"},"publishJUnitResults":{"type":"boolean","description":"Publish to Azure Pipelines","ignoreCase":"key"},"testResultsFiles":{"type":"string","description":"Test Results Files","ignoreCase":"key"},"testRunTitle":{"type":"string","description":"Test Run Title","ignoreCase":"key"},"enableCodeCoverage":{"type":"boolean","description":"Enable code Coverage","ignoreCase":"key"},"testFramework":{"description":"Test Framework","ignoreCase":"all","enum":["Mocha","Jasmine"]},"srcFiles":{"type":"string","description":"Source Files","ignoreCase":"key"},"testFiles":{"type":"string","description":"Test Script Files","ignoreCase":"key"}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]},{"properties":{"task":{"description":"Cloud-based web performance test\n\nRun a quick web performance test in the cloud with Azure Pipelines","ignoreCase":"value","pattern":"^QuickPerfTest@1$"},"inputs":{"description":"Cloud-based web performance test inputs","properties":{"connectedServiceName":{"type":"string","description":"Azure Pipelines Connection","ignoreCase":"key"},"websiteUrl":{"type":"string","description":"Website URL","ignoreCase":"key"},"testName":{"type":"string","description":"Test Name","ignoreCase":"key"},"vuLoad":{"description":"User Load","ignoreCase":"all","enum":["25","50","100","250"]},"runDuration":{"description":"Run Duration (sec)","ignoreCase":"all","enum":["60","120","180","240","300"]},"geoLocation":{"description":"Load Location","ignoreCase":"all","enum":["Default","Australia East","Australia Southeast","Brazil South","Central India","Central US","East Asia","East US 2","East US","Japan East","Japan West","North Central US","North Europe","South Central US","South India","Southeast Asia","West Europe","West US"]},"machineType":{"description":"Run load test using","ignoreCase":"all","enum":["0","2"]},"resourceGroupName":{"type":"string","description":"Resource group rig","ignoreCase":"key"},"numOfSelfProvisionedAgents":{"type":"integer","description":"No. of agents to use","ignoreCase":"key"},"avgResponseTimeThreshold":{"type":"string","description":"Fail test if Avg.Response Time(ms) exceeds","ignoreCase":"key"}},"additionalProperties":false,"required":["websiteUrl","testName"]}},"deprecationMessage":"QuickPerfTest is deprecated - Run a quick web performance test in the cloud with Azure Pipelines","doNotSuggest":true,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"IIS web app manage\n\nCreate or update websites, web apps, virtual directories, or application pools","ignoreCase":"value","pattern":"^IISWebAppManagementOnMachineGroup@0$"},"inputs":{"description":"IIS web app manage inputs","properties":{"EnableIIS":{"type":"boolean","description":"Enable IIS","ignoreCase":"key"},"IISDeploymentType":{"description":"Configuration type","ignoreCase":"all","enum":["IISWebsite","IISWebApplication","IISVirtualDirectory","IISApplicationPool"]},"ActionIISWebsite":{"description":"Action","ignoreCase":"all","enum":["CreateOrUpdateWebsite","StartWebsite","StopWebsite"]},"ActionIISApplicationPool":{"description":"Action","ignoreCase":"all","enum":["CreateOrUpdateAppPool","StartAppPool","StopAppPool","RecycleAppPool"]},"StartStopWebsiteName":{"type":"string","description":"Website name","ignoreCase":"key"},"WebsiteName":{"type":"string","description":"Website name","ignoreCase":"key"},"WebsitePhysicalPath":{"type":"string","description":"Physical path","ignoreCase":"key"},"WebsitePhysicalPathAuth":{"description":"Physical path authentication","ignoreCase":"all","enum":["WebsiteUserPassThrough","WebsiteWindowsAuth"]},"WebsiteAuthUserName":{"type":"string","description":"Username","ignoreCase":"key"},"WebsiteAuthUserPassword":{"type":"string","description":"Password","ignoreCase":"key"},"AddBinding":{"type":"boolean","description":"Add binding","ignoreCase":"key"},"Protocol":{"description":"Protocol","ignoreCase":"all","enum":["https","http"]},"IPAddress":{"type":"string","description":"IP address","ignoreCase":"key"},"Port":{"type":"string","description":"Port","ignoreCase":"key"},"ServerNameIndication":{"type":"boolean","description":"Server Name Indication required","ignoreCase":"key"},"HostNameWithOutSNI":{"type":"string","description":"Host name","ignoreCase":"key"},"HostNameWithHttp":{"type":"string","description":"Host name","ignoreCase":"key"},"HostNameWithSNI":{"type":"string","description":"Host name","ignoreCase":"key"},"SSLCertThumbPrint":{"type":"string","description":"SSL certificate thumbprint","ignoreCase":"key"},"Bindings":{"type":"string","description":"Add bindings","ignoreCase":"key"},"CreateOrUpdateAppPoolForWebsite":{"type":"boolean","description":"Create or update app pool","ignoreCase":"key"},"ConfigureAuthenticationForWebsite":{"type":"boolean","description":"Configure authentication","ignoreCase":"key"},"AppPoolNameForWebsite":{"type":"string","description":"Name","ignoreCase":"key"},"DotNetVersionForWebsite":{"description":".NET version","ignoreCase":"all","enum":["v4.0","v2.0","No Managed Code"]},"PipeLineModeForWebsite":{"description":"Managed pipeline mode","ignoreCase":"all","enum":["Integrated","Classic"]},"AppPoolIdentityForWebsite":{"description":"Identity","ignoreCase":"all","enum":["ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"]},"AppPoolUsernameForWebsite":{"type":"string","description":"Username","ignoreCase":"key"},"AppPoolPasswordForWebsite":{"type":"string","description":"Password","ignoreCase":"key"},"AnonymousAuthenticationForWebsite":{"type":"boolean","description":"Anonymous authentication","ignoreCase":"key"},"BasicAuthenticationForWebsite":{"type":"boolean","description":"Basic authentication","ignoreCase":"key"},"WindowsAuthenticationForWebsite":{"type":"boolean","description":"Windows authentication","ignoreCase":"key"},"ParentWebsiteNameForVD":{"type":"string","description":"Parent website name","ignoreCase":"key"},"VirtualPathForVD":{"type":"string","description":"Virtual path","ignoreCase":"key"},"PhysicalPathForVD":{"type":"string","description":"Physical path","ignoreCase":"key"},"VDPhysicalPathAuth":{"description":"Physical path authentication","ignoreCase":"all","enum":["VDUserPassThrough","VDWindowsAuth"]},"VDAuthUserName":{"type":"string","description":"Username","ignoreCase":"key"},"VDAuthUserPassword":{"type":"string","description":"Password","ignoreCase":"key"},"ParentWebsiteNameForApplication":{"type":"string","description":"Parent website name","ignoreCase":"key"},"VirtualPathForApplication":{"type":"string","description":"Virtual path","ignoreCase":"key"},"PhysicalPathForApplication":{"type":"string","description":"Physical path","ignoreCase":"key"},"ApplicationPhysicalPathAuth":{"description":"Physical path authentication","ignoreCase":"all","enum":["ApplicationUserPassThrough","ApplicationWindowsAuth"]},"ApplicationAuthUserName":{"type":"string","description":"Username","ignoreCase":"key"},"ApplicationAuthUserPassword":{"type":"string","description":"Password","ignoreCase":"key"},"CreateOrUpdateAppPoolForApplication":{"type":"boolean","description":"Create or update app pool","ignoreCase":"key"},"AppPoolNameForApplication":{"type":"string","description":"Name","ignoreCase":"key"},"DotNetVersionForApplication":{"description":".NET version","ignoreCase":"all","enum":["v4.0","v2.0","No Managed Code"]},"PipeLineModeForApplication":{"description":"Managed pipeline mode","ignoreCase":"all","enum":["Integrated","Classic"]},"AppPoolIdentityForApplication":{"description":"Identity","ignoreCase":"all","enum":["ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"]},"AppPoolUsernameForApplication":{"type":"string","description":"Username","ignoreCase":"key"},"AppPoolPasswordForApplication":{"type":"string","description":"Password","ignoreCase":"key"},"AppPoolName":{"type":"string","description":"Name","ignoreCase":"key"},"DotNetVersion":{"description":".NET version","ignoreCase":"all","enum":["v4.0","v2.0","No Managed Code"]},"PipeLineMode":{"description":"Managed pipeline mode","ignoreCase":"all","enum":["Integrated","Classic"]},"AppPoolIdentity":{"description":"Identity","ignoreCase":"all","enum":["ApplicationPoolIdentity","LocalService","LocalSystem","NetworkService","SpecificUser"]},"AppPoolUsername":{"type":"string","description":"Username","ignoreCase":"key"},"AppPoolPassword":{"type":"string","description":"Password","ignoreCase":"key"},"StartStopRecycleAppPoolName":{"type":"string","description":"Application pool name","ignoreCase":"key"},"AppCmdCommands":{"type":"string","description":"Additional appcmd.exe commands","ignoreCase":"key"}},"additionalProperties":false,"required":["WebsiteName","Bindings","AppPoolNameForWebsite","ParentWebsiteNameForVD","VirtualPathForVD","ParentWebsiteNameForApplication","VirtualPathForApplication","AppPoolNameForApplication","AppPoolName"]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task","inputs"]},{"properties":{"task":{"description":"Docker CLI installer\n\nInstall Docker CLI on agent machine.","ignoreCase":"value","pattern":"^DockerInstaller@0$"},"inputs":{"description":"Docker CLI installer inputs","properties":{"dockerVersion":{"type":"string","description":"Docker Version","ignoreCase":"key"},"releaseType":{"description":"Release type","ignoreCase":"all","enum":["stable","edge","test","nightly"]}},"additionalProperties":false,"required":[]}},"doNotSuggest":false,"firstProperty":["task"],"required":["task"]}]}}} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000000..68f5ac8166497 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "ms-dotnettools.csharp", + "EditorConfig.EditorConfig", + "ms-vscode.powershell", + "tintoy.msbuild-project-tools", + "ms-azure-devops.azure-pipelines" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 5c446623b4d14..ed98c2caad160 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,9 +10,9 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/artifacts/bin/BuildValidator/Debug/netcoreapp3.1/BuildValidator.dll", + "program": "${workspaceFolder}/artifacts/bin/BuildValidator/Debug/net6.0/BuildValidator.dll", "args": [ - "--assembliesPath", "./artifacts/obj/csc/Debug/netcoreapp3.1", + "--assembliesPath", "./artifacts/obj/csc/Debug/net6.0", "--referencesPath", "./artifacts/bin", "--referencesPath", "C:/Program Files/dotnet/packs/Microsoft.AspNetCore.App.Ref", "--referencesPath", "C:/Program Files/dotnet/packs/Microsoft.NETCore.App.Ref", @@ -29,8 +29,8 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/artifacts/bin/RunTests/Debug/netcoreapp3.1/RunTests.dll", - "args": ["--tfm", "netcoreapp3.1", "--sequential", "--html"], + "program": "${workspaceFolder}/artifacts/bin/RunTests/Debug/net6.0/RunTests.dll", + "args": ["--tfm", "net6.0", "--sequential", "--html"], "cwd": "${workspaceFolder}/artifacts/bin/RunTests", "stopAtEntry": false, "console": "internalConsole" @@ -41,7 +41,7 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/artifacts/bin/PrepareTests/Debug/net5.0/PrepareTests.dll", + "program": "${workspaceFolder}/artifacts/bin/PrepareTests/Debug/net6.0/PrepareTests.dll", "args": [ "--source", "${workspaceFolder}", "--destination", "${workspaceFolder}/artifacts/testPayload" @@ -70,4 +70,4 @@ "processId": "${command:pickProcess}" } ] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 399accea7023f..30d1af265a8ec 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,38 @@ { "files.associations": { - "**/eng/pipelines/*.yml": "azure-pipelines" + "*.csproj": "msbuild", + "*.fsproj": "msbuild", + "*.globalconfig": "ini", + "*.manifest": "xml", + "*.nuspec": "xml", + "*.pkgdef": "ini", + "*.projitems": "msbuild", + "*.props": "msbuild", + "*.resx": "xml", + "*.rsp": "Powershell", + "*.ruleset": "xml", + "*.settings": "xml", + "*.shproj": "msbuild", + "*.slnf": "json", + "*.targets": "msbuild", + "*.vbproj": "msbuild", + "*.vsixmanifest": "xml", + "*.vstemplate": "xml", + "*.xlf": "xml", + "*.yml": "azure-pipelines" }, + // ms-dotnettools.csharp settings "omnisharp.defaultLaunchSolution": "Compilers.sln", + "omnisharp.disableMSBuildDiagnosticWarning": true, + "omnisharp.enableEditorConfigSupport": true, + "omnisharp.enableImportCompletion": true, + "omnisharp.enableRoslynAnalyzers": true, + "omnisharp.useModernNet": true, + "omnisharp.enableAsyncCompletion": true, + // ms-vscode.powershell settings + "powershell.promptToUpdatePowerShell": false, + "powershell.integratedConsole.showOnStartup": false, + "powershell.startAutomatically": false, + // ms-azure-devops.azure-pipelines settings + "azure-pipelines.customSchemaFile": ".vscode/dnceng-schema.json" } \ No newline at end of file diff --git a/NuGet.config b/NuGet.config index 8c879770d5df4..513b93df1e591 100644 --- a/NuGet.config +++ b/NuGet.config @@ -7,6 +7,7 @@ + diff --git a/Roslyn.sln b/Roslyn.sln index ac71fe97c7d3a..b90c9e295369f 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -246,8 +246,6 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Microsoft.CodeAnalysis.Visu EndProject Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Microsoft.CodeAnalysis.VisualBasic.Scripting.UnitTests", "src\Scripting\VisualBasicTest\Microsoft.CodeAnalysis.VisualBasic.Scripting.UnitTests.vbproj", "{ABC7262E-1053-49F3-B846-E3091BB92E8C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roslyn.Hosting.Diagnostics", "src\Test\Diagnostics\Roslyn.Hosting.Diagnostics.csproj", "{E2E889A5-2489-4546-9194-47C63E49EAEB}" -EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "BasicAnalyzerDriver", "src\Compilers\VisualBasic\BasicAnalyzerDriver\BasicAnalyzerDriver.shproj", "{E8F0BAA5-7327-43D1-9A51-644E81AE55F1}" EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "CSharpAnalyzerDriver", "src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.shproj", "{54E08BF5-F819-404F-A18D-0AB9EA81EA04}" @@ -958,10 +956,6 @@ Global {ABC7262E-1053-49F3-B846-E3091BB92E8C}.Debug|Any CPU.Build.0 = Debug|Any CPU {ABC7262E-1053-49F3-B846-E3091BB92E8C}.Release|Any CPU.ActiveCfg = Release|Any CPU {ABC7262E-1053-49F3-B846-E3091BB92E8C}.Release|Any CPU.Build.0 = Release|Any CPU - {E2E889A5-2489-4546-9194-47C63E49EAEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E2E889A5-2489-4546-9194-47C63E49EAEB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E2E889A5-2489-4546-9194-47C63E49EAEB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E2E889A5-2489-4546-9194-47C63E49EAEB}.Release|Any CPU.Build.0 = Release|Any CPU {43026D51-3083-4850-928D-07E1883D5B1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {43026D51-3083-4850-928D-07E1883D5B1A}.Debug|Any CPU.Build.0 = Debug|Any CPU {43026D51-3083-4850-928D-07E1883D5B1A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -1419,7 +1413,6 @@ Global {286B01F3-811A-40A7-8C1F-10C9BB0597F7} = {38940C5F-97FD-4B2A-B2CD-C4E4EF601B05} {24973B4C-FD09-4EE1-97F4-EA03E6B12040} = {38940C5F-97FD-4B2A-B2CD-C4E4EF601B05} {ABC7262E-1053-49F3-B846-E3091BB92E8C} = {38940C5F-97FD-4B2A-B2CD-C4E4EF601B05} - {E2E889A5-2489-4546-9194-47C63E49EAEB} = {8DBA5174-B0AA-4561-82B1-A46607697753} {E8F0BAA5-7327-43D1-9A51-644E81AE55F1} = {C65C6143-BED3-46E6-869E-9F0BE6E84C37} {54E08BF5-F819-404F-A18D-0AB9EA81EA04} = {32A48625-F0AD-419D-828B-A50BDABA38EA} {AD6F474E-E6D4-4217-91F3-B7AF1BE31CCC} = {A41D1B99-F489-4C43-BBDF-96D61B19A6B9} diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt index af2976dd66b8c..30ed202c8ebe0 100644 --- a/THIRD-PARTY-NOTICES.txt +++ b/THIRD-PARTY-NOTICES.txt @@ -78,3 +78,34 @@ 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. + + +License notice for Json.NET +------------------------------------- + +https://github.com/JamesNK/Newtonsoft.Json + +Copyright (c) 2007 James Newton-King + +This software is licensed subject to the MIT license, available at +https://opensource.org/licenses/MIT + +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. + + +JSON Parsing Test Suite +------------------------------------- + +https://github.com/nst/JSONTestSuite + +Copyright (c) 2016 Nicolas Seriot + +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. diff --git a/azure-pipelines-integration-dartlab.yml b/azure-pipelines-integration-dartlab.yml index 63f243e7f1de4..3744c777f092d 100644 --- a/azure-pipelines-integration-dartlab.yml +++ b/azure-pipelines-integration-dartlab.yml @@ -1,6 +1,7 @@ # Roslyn integration test pipeline for validating against branch builds of VS. trigger: none # Manual trigger for now +pr: none # Manual trigger for now resources: pipelines: @@ -15,6 +16,13 @@ resources: type: git name: DartLab.Templates ref: refs/heads/dev/bradwhit/RemoveCheckoutNone + - repository: RoslynMirror + endpoint: dnceng/internal dotnet-roslyn + type: git + name: internal/dotnet-roslyn + ref: $(Build.SourceBranchName) + trigger: + - main variables: - name: XUNIT_LOGS @@ -54,6 +62,7 @@ stages: filePath: $(DartLab.Path)\Scripts\VisualStudio\Build\Get-VisualStudioDropName.ps1 arguments: -DropNamePrefix 'Products' -VstsDropUrlsJson '$(Pipeline.Workspace)\VisualStudioBuildUnderTest\BuildArtifacts\VstsDropUrls.json' -OutVariableName 'VisualStudio.BuildUnderTest.ProductsDropName' deployAndRunTestsStepList: + - checkout: RoslynMirror - template: eng/pipelines/test-integration-job.yml parameters: configuration: $(_configuration) diff --git a/azure-pipelines-official.yml b/azure-pipelines-official.yml index 0b84738c2d3fc..e43cb5206ac23 100644 --- a/azure-pipelines-official.yml +++ b/azure-pipelines-official.yml @@ -122,7 +122,7 @@ stages: # Authenticate with service connections to be able to publish packages to external nuget feeds. - task: NuGetAuthenticate@0 inputs: - nuGetServiceConnections: azure-public/vs-impl, azure-public/vssdk, devdiv/engineering + nuGetServiceConnections: azure-public/vs-impl, azure-public/vssdk, devdiv/engineering, devdiv/dotnet-core-internal-tooling # Needed because the build fails the NuGet Tools restore without it - task: UseDotNet@2 @@ -296,7 +296,8 @@ stages: dependsOn: - OfficialBuild pool: - vmImage: windows-2019 + name: NetCore1ESPool-Svc-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 - stage: insert dependsOn: @@ -307,7 +308,8 @@ stages: - job: insert displayName: Insert to VS pool: - vmImage: windows-2019 + name: NetCore1ESPool-Svc-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - powershell: | $branchName = "$(Build.SourceBranch)".Substring("refs/heads/".Length) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6e0c9a95799d7..48690528fc45a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -146,7 +146,7 @@ jobs: testArtifactName: Transport_Artifacts_Unix_Debug configuration: Debug testArguments: --testCoreClr - queueName: 'Build.Ubuntu.1804.amd64.Open' + queueName: Build.Ubuntu.1804.Amd64.Open - template: eng/pipelines/test-unix-job.yml parameters: diff --git a/docs/Breaking API Changes.md b/docs/Breaking API Changes.md index 0d650b2547e28..bad7316b5b043 100644 --- a/docs/Breaking API Changes.md +++ b/docs/Breaking API Changes.md @@ -52,4 +52,11 @@ PR: https://github.com/dotnet/roslyn/pull/11536 ### Can no longer inherit from CompletionService and CompletionServiceWithProviders The constructors of Microsoft.CodeAnalysis.Completion and Microsoft.CodeAnalysis.Completion.CompletionServiceWithProviders are now internal. +Roslyn does not support implementing completion for arbitrary languages. + +# Version 4.2.0 + +### Can no longer inherit from QuickInfoService + +The constructors of Microsoft.CodeAnalysis.QuickInfoService are now internal. Roslyn does not support implementing completion for arbitrary languages. \ No newline at end of file diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md index 6676470c7d0e8..b73efb63ebaee 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -12,17 +12,23 @@ efforts behind them. | ------- | ------ | ----- | --------- | -------- | --------- | | [Newlines in interpolations](https://github.com/dotnet/csharplang/issues/4935) | main | [Merged in 17.1p1](https://github.com/dotnet/roslyn/issues/57154) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv), [chsienki](https://github.com/chsienki) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [List patterns](https://github.com/dotnet/csharplang/issues/3435) | [list-patterns](https://github.com/dotnet/roslyn/tree/features/list-patterns) | [Merged in 17.1p2](https://github.com/dotnet/roslyn/issues/51289) | [alrz](https://github.com/alrz) | [jcouv](https://github.com/jcouv), [333fred](https://github.com/333fred) | [333fred](https://github.com/333fred) | -| [Parameter null-checking](https://github.com/dotnet/csharplang/issues/2145) | [param-nullchecking](https://github.com/dotnet/roslyn/tree/features/param-nullchecking) | [In Progress](https://github.com/dotnet/roslyn/issues/36024) | [RikkiGibson](https://github.com/RikkiGibson), [fayrose](https://github.com/fayrose) | [cston](https://github.com/cston), [chsienki](https://github.com/chsienki) | [jaredpar](https://github.com/jaredpar) | -| [Raw string literals](https://github.com/dotnet/csharplang/issues/4304) | [RawStringLiterals](https://github.com/dotnet/roslyn/tree/features/RawStringLiterals) | [In Progress](https://github.com/dotnet/roslyn/issues/55306) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | +| [Parameter null-checking](https://github.com/dotnet/csharplang/issues/2145) | [param-nullchecking](https://github.com/dotnet/roslyn/tree/features/param-nullchecking) | [Merged in 17.1p3](https://github.com/dotnet/roslyn/issues/36024) | [RikkiGibson](https://github.com/RikkiGibson), [fayrose](https://github.com/fayrose) | [cston](https://github.com/cston), [chsienki](https://github.com/chsienki) | [jaredpar](https://github.com/jaredpar) | +| [Raw string literals](https://github.com/dotnet/csharplang/issues/4304) | [RawStringLiterals](https://github.com/dotnet/roslyn/tree/features/RawStringLiterals) | [Merged into 17.2](https://github.com/dotnet/roslyn/issues/55306) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | +| [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 | [In Progress](https://github.com/dotnet/roslyn/issues/40524) | [jcouv](https://github.com/jcouv) | TBD | [jcouv](https://github.com/jcouv) | | [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) | [required-members](https://github.com/dotnet/roslyn/tree/features/required-members) | [In Progress](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) | TBD | [jaredpar](https://github.com/jaredpar) | +| [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) | +| [Pattern matching on `ReadOnlySpan`](https://github.com/dotnet/csharplang/issues/1881) | [patterns-span-char](https://github.com/dotnet/roslyn/tree/features/patterns-span-char) | [In Progress](https://github.com/dotnet/roslyn/issues/59191) | [YairHalberstadt ](https://github.com/YairHalberstadt) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv) | +| [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) | +| [Utf8 String Literals](https://github.com/dotnet/csharplang/issues/184) | [Utf8StringLiterals](https://github.com/dotnet/roslyn/tree/features/Utf8StringLiterals) | [In Progress](https://github.com/dotnet/roslyn/issues/58848) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [MadsTorgersen](https://github.com/MadsTorgersen) | +| [ref fields](https://github.com/dotnet/csharplang/blob/main/proposals/low-level-struct-improvements.md) | TBD | [In Progress](https://github.com/dotnet/roslyn/issues/59194) | TBD | TBD | [jaredpar](https://github.com/jaredpar) | +| [checked operators](https://github.com/dotnet/csharplang/issues/4665) | [CheckedUserDefinedOperators](https://github.com/dotnet/roslyn/tree/features/CheckedUserDefinedOperators) | [In Progress](https://github.com/dotnet/roslyn/issues/59458) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [chsienki](https://github.com/chsienki) | [AlekseyTs](https://github.com/AlekseyTs) | # C# 10.0 diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md index a530a0ab2d7dc..478fca0892c81 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 6.md @@ -108,3 +108,24 @@ These are _function_type_conversions_. } } ``` + +4. In Visual Studio 17.1, `struct` type declarations with field initializers must include an explicitly declared constructor. Additionally, all fields must be definitely assigned in `struct` instance constructors that do not have a `: this()` initializer so any previously unassigned fields must be assigned from the added constructor or from field initializers. + + For instance, the following results in an error in 17.1: + ```csharp + struct S + { + int X = 1; // error: struct with field initializers must include an explicitly declared constructor + int Y; + } + ``` + + The error could be resolved by adding a constructor and assigning the other field. + ```csharp + struct S + { + int X = 1; + int Y; + public S() { Y = 0; } // ok + } + ``` diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index 3239e1081ddcf..acfba8bddc569 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md @@ -68,7 +68,7 @@ Those types can be used with implicit Index indexer and list patterns. ``` 5. Starting with Visual Studio 17.1, format specifiers in interpolated strings can not contain curly braces (either `{` or `}`). In previous versions `{{` was interpreted as an escaped `{` and `}}` was interpreted as an escaped `}` char in the format specifier. Now the first `}` char in a format specifier ends the interpolation, and any `{` char is an error. -https://github.com/dotnet/roslyn/issues/5775 +https://github.com/dotnet/roslyn/issues/57750 ```csharp using System; @@ -77,12 +77,3 @@ https://github.com/dotnet/roslyn/issues/5775 //prints now: "{C}" - not "{X}}" ``` - -6. Starting with Visual Studio 17.1, `struct` type declarations with field initializers must include an explicitly declared constructor. - - ```csharp - struct S - { - int X = 1; // error: struct with field initializers must include an explicitly declared constructor - } - ``` diff --git a/docs/compilers/CSharp/Warnversion Warning Waves.md b/docs/compilers/CSharp/Warnversion Warning Waves.md index adb8e93bd4699..683d44893051d 100644 --- a/docs/compilers/CSharp/Warnversion Warning Waves.md +++ b/docs/compilers/CSharp/Warnversion Warning Waves.md @@ -7,30 +7,41 @@ without taking action to enable them. For that purpose, we have the compiler flag "`/warn:n`" where `n` is a whole number. -The compiler shipped with dotnet 5 (the C# 9 compiler) contains some warnings, documented below, that -are reported only under `/warn:5` or higher. - -The default warning level when the command-line compiler is used is `4`. - -If you want the compiler to produce all applicable warnings, you can specify -`/warn:9999`. - -The table below describes all of the warnings controlled by warning levels `5` or greater. - -| Warning ID | warning level | Description | -|------------|---------|-------------| -| CS7023 | 5 | [A static type is used in an 'is' or 'as' expression](https://github.com/dotnet/roslyn/issues/30198) | -| CS8073 | 5 | [Expression always true (or false) when comparing a struct to null](https://github.com/dotnet/roslyn/issues/45744) | -| CS8848 | 5 | [Diagnose precedence error with query expression](https://github.com/dotnet/roslyn/issues/30231) | -| CS8880 | 5 | [Struct constructor does not assign auto property (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | -| CS8881 | 5 | [Struct constructor does not assign field (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | -| CS8882 | 5 | [Out parameter not assigned (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | -| CS8883 | 5 | [Auto-property used before assigned in struct constructor (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | -| CS8884 | 5 | [Field used before assigned in struct constructor (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | -| CS8885 | 5 | [Struct constructor reads 'this' before assigning all fields (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | -| CS8886 | 5 | [Out parameter used before being assigned (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | -| CS8887 | 5 | [Local variable used before being assigned (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | -| CS8892 | 5 | [Multiple entry points](https://github.com/dotnet/roslyn/issues/46831) | -| CS8897 | 5 | [Static class used as the parameter type of a method in an interface type](https://github.com/dotnet/roslyn/issues/38256) | -| CS8898 | 5 | [Static class used as the return type of a method in an interface type](https://github.com/dotnet/roslyn/issues/38256) | -| CS8981 | 7 | [Type names only containing lower-cased ascii characters may become reserved for the language](https://github.com/dotnet/roslyn/issues/56653) | +The default warning level when the command-line compiler is used is `4`. If you want the compiler to produce all applicable warnings, you can specify `/warn:9999`. + +## Warning level 7 + +The compiler shipped with .NET 7 (the C# 11 compiler) contains the following warnings which are reported only under `/warn:7` or higher. + +| Warning ID | Description | +|------------|-------------| +| CS8981 | [Type names only containing lower-cased ascii characters may become reserved for the language](https://github.com/dotnet/roslyn/issues/56653) | + +# Warning level 6 + +The compiler shipped with .NET 6 (the C# 10 compiler) contains the following warnings which are reported only under `/warn:6` or higher. + +| Warning ID | Description | +|------------|-------------| +| CS8826 | [Partial method declarations have signature differences](https://github.com/dotnet/roslyn/issues/47838) | + +## Warning level 5 + +The compiler shipped with .NET 5 (the C# 9 compiler) contains the following warnings which are reported only under `/warn:5` or higher. + +| Warning ID | Description | +|------------|-------------| +| CS7023 | [A static type is used in an 'is' or 'as' expression](https://github.com/dotnet/roslyn/issues/30198) | +| CS8073 | [Expression always true (or false) when comparing a struct to null](https://github.com/dotnet/roslyn/issues/45744) | +| CS8848 | [Diagnose precedence error with query expression](https://github.com/dotnet/roslyn/issues/30231) | +| CS8880 | [Struct constructor does not assign auto property (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | +| CS8881 | [Struct constructor does not assign field (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | +| CS8882 | [Out parameter not assigned (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | +| CS8883 | [Auto-property used before assigned in struct constructor (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | +| CS8884 | [Field used before assigned in struct constructor (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | +| CS8885 | [Struct constructor reads 'this' before assigning all fields (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | +| CS8886 | [Out parameter used before being assigned (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | +| CS8887 | [Local variable used before being assigned (imported struct type with private fields)](https://github.com/dotnet/roslyn/issues/30194) | +| CS8892 | [Multiple entry points](https://github.com/dotnet/roslyn/issues/46831) | +| CS8897 | [Static class used as the parameter type of a method in an interface type](https://github.com/dotnet/roslyn/issues/38256) | +| CS8898 | [Static class used as the return type of a method in an interface type](https://github.com/dotnet/roslyn/issues/38256) | diff --git a/docs/contributing/Building, Debugging, and Testing on Windows.md b/docs/contributing/Building, Debugging, and Testing on Windows.md index aa8bd58444844..f3f6be666bf54 100644 --- a/docs/contributing/Building, Debugging, and Testing on Windows.md +++ b/docs/contributing/Building, Debugging, and Testing on Windows.md @@ -15,9 +15,8 @@ The minimal required version of .NET Framework is 4.7.2. ## Developing with Visual Studio 2022 -1. [Visual Studio 2022 17.0 Preview](https://visualstudio.microsoft.com/vs/preview/vs2022/) +1. Use latest [Visual Studio 2022 Preview](https://visualstudio.microsoft.com/vs/preview/vs2022/) - Ensure C#, VB, MSBuild, .NET Core and Visual Studio Extensibility are included in the selected work loads - - Ensure Visual Studio is on Version "17.0" or greater - Ensure "Use previews of the .NET Core SDK" is checked in Tools -> Options -> Environment -> Preview Features - Restart Visual Studio 1. [.NET 6.0 SDK](https://dotnet.microsoft.com/download/dotnet-core/6.0) [Windows x64 installer](https://dotnet.microsoft.com/download/dotnet/thank-you/sdk-6.0.100-windows-x64-installer) diff --git a/docs/contributing/Compiler Test Plan.md b/docs/contributing/Compiler Test Plan.md index 2de380f764673..2abe570bdef9c 100644 --- a/docs/contributing/Compiler Test Plan.md +++ b/docs/contributing/Compiler Test Plan.md @@ -57,6 +57,7 @@ This document provides guidance for thinking about language interactions and tes - Partial method - Named and optional parameters - String interpolation +- Raw strings (including interpolation) - Properties (read-write, read-only, init-only, write-only, auto-property, expression-bodied) - Interfaces (implicit vs. explicit interface member implementation) - Delegates diff --git a/docs/features/source-generators.cookbook.md b/docs/features/source-generators.cookbook.md index 5ef562d10b60b..e5e8a79626a46 100644 --- a/docs/features/source-generators.cookbook.md +++ b/docs/features/source-generators.cookbook.md @@ -997,7 +997,6 @@ private static string Generate(ClassDeclarationSyntax c) sb.Append("\\\""); } sb.AppendLine(",\");"); - break; } } diff --git a/dotnet-tools.json b/dotnet-tools.json index 0d36407e3c7fa..c232231ac428f 100644 --- a/dotnet-tools.json +++ b/dotnet-tools.json @@ -2,7 +2,7 @@ "isRoot": true, "tools": { "dotnet-format": { - "version": "6.0.240501", + "version": "6.0.257007", "commands": [ "dotnet-format" ] diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ebb6fdb7f29e5..646f210ed6971 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -13,18 +13,18 @@ - + https://github.com/dotnet/arcade - a0f6d2432ce3d1bb30ee747bb534f477c75fd667 + 4d6406fa2e84c8516a338694be3a4097e6e1f104 - + https://github.com/dotnet/roslyn - 818313426323d979747781a17c78860c833776da + 592501cbb9c9394072a245c15b3458ff88155d85 - + https://github.com/dotnet/arcade - a0f6d2432ce3d1bb30ee747bb534f477c75fd667 + 4d6406fa2e84c8516a338694be3a4097e6e1f104 diff --git a/eng/Versions.props b/eng/Versions.props index f6252f44be69c..5bc5160f1b8b5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -8,36 +8,28 @@ 4 2 0 - 1 + 2 $(MajorVersion).$(MinorVersion).$(PatchVersion) $(MajorVersion).$(MinorVersion).0.0 - - - - - - 4.1.0-2.21609.7 + 4.1.0-3.22075.3 3.3.3-beta1.21105.3 6.0.0-rc1.21366.2 - 1.1.1-beta1.21480.3 - 0.1.122-beta + 1.1.1-beta1.22081.4 + 0.1.124-beta - 4.0.0-3.final + 4.0.1 16.10.230 17.0.487 5.0.0-alpha1.19409.1 5.0.0-preview.1.20112.8 - 17.1.3 + 17.1.11 17.0.31723.112 16.5.0 3.8.0 + 7.0.0-alpha.1.22060.1 - 4.7.0 - 5.0.0 + 6.0.0 + 6.0.0 4.5.0 4.5.4 @@ -274,14 +267,14 @@ create a test insertion in Visual Studio to validate. --> 13.0.1 - 2.8.28 + 2.11.14-alpha 5.0.0 5.0.0 - 5.0.0 + 6.0.0 true diff --git a/eng/build.ps1 b/eng/build.ps1 index cce06b6603676..f9cc3577e3ddb 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -585,6 +585,7 @@ function Deploy-VsixViaTool() { # Configure LSP $lspRegistryValue = [int]$lspEditor.ToBool() &$vsRegEdit set "$vsDir" $hive HKCU "FeatureFlags\Roslyn\LSP\Editor" Value dword $lspRegistryValue + &$vsRegEdit set "$vsDir" $hive HKCU "FeatureFlags\Lsp\PullDiagnostics" Value dword $lspRegistryValue # Disable text editor error reporting because it pops up a dialog. We want to either fail fast in our # custom handler or fail silently and continue testing. diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index e94d13d62ef64..f97dca7705408 100755 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -7,7 +7,7 @@ usage() echo "Usage: $0 [BuildArch] [CodeName] [lldbx.y] [--skipunmount] --rootfsdir ]" echo "BuildArch can be: arm(default), armel, arm64, x86" echo "CodeName - optional, Code name for Linux, can be: xenial(default), zesty, bionic, alpine, alpine3.13 or alpine3.14. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen." - echo " for FreeBSD can be: freebsd11, freebsd12, freebsd13" + echo " for FreeBSD can be: freebsd12, freebsd13" echo " for illumos can be: illumos." echo "lldbx.y - optional, LLDB version, can be: lldb3.9(default), lldb4.0, lldb5.0, lldb6.0 no-lldb. Ignored for alpine and FreeBSD" echo "--skipunmount - optional, will skip the unmount of rootfs folder." @@ -60,13 +60,13 @@ __AlpinePackages+=" krb5-dev" __AlpinePackages+=" openssl-dev" __AlpinePackages+=" zlib-dev" -__FreeBSDBase="12.2-RELEASE" -__FreeBSDPkg="1.12.0" +__FreeBSDBase="12.3-RELEASE" +__FreeBSDPkg="1.17.0" __FreeBSDABI="12" __FreeBSDPackages="libunwind" __FreeBSDPackages+=" icu" __FreeBSDPackages+=" libinotify" -__FreeBSDPackages+=" lttng-ust" +__FreeBSDPackages+=" openssl" __FreeBSDPackages+=" krb5" __FreeBSDPackages+=" terminfo-db" @@ -206,10 +206,6 @@ while :; do __AlpineVersion=3.14 __AlpinePackages+=" llvm11-libs" ;; - freebsd11) - __FreeBSDBase="11.3-RELEASE" - __FreeBSDABI="11" - ;& freebsd12) __CodeName=freebsd __BuildArch=x64 diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index f7878dddd3921..fba2afda438b6 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -37,6 +37,13 @@ elseif(TARGET_ARCH_NAME STREQUAL "arm") if(TIZEN) set(TIZEN_TOOLCHAIN "armv7hl-tizen-linux-gnueabihf/9.2.0") endif() +elseif(TARGET_ARCH_NAME STREQUAL "armv6") + set(CMAKE_SYSTEM_PROCESSOR armv6l) + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf) + set(TOOLCHAIN "armv6-alpine-linux-musleabihf") + else() + set(TOOLCHAIN "arm-linux-gnueabihf") + endif() elseif(TARGET_ARCH_NAME STREQUAL "arm64") set(CMAKE_SYSTEM_PROCESSOR aarch64) if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-alpine-linux-musl) @@ -60,7 +67,7 @@ elseif (ILLUMOS) set(CMAKE_SYSTEM_PROCESSOR "x86_64") set(TOOLCHAIN "x86_64-illumos") else() - message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, arm64, s390x and x86 are supported!") + message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, armv6, arm64, s390x and x86 are supported!") endif() if(DEFINED ENV{TOOLCHAIN}) @@ -194,7 +201,7 @@ endif() # Specify compile options -if((TARGET_ARCH_NAME MATCHES "^(arm|armel|arm64|s390x)$" AND NOT ANDROID) OR ILLUMOS) +if((TARGET_ARCH_NAME MATCHES "^(arm|armv6|armel|arm64|s390x)$" AND NOT ANDROID) OR ILLUMOS) set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN}) diff --git a/eng/common/generate-graph-files.ps1 b/eng/common/generate-graph-files.ps1 deleted file mode 100644 index 0728b1a8b570d..0000000000000 --- a/eng/common/generate-graph-files.ps1 +++ /dev/null @@ -1,86 +0,0 @@ -Param( - [Parameter(Mandatory=$true)][string] $barToken, # Token generated at https://maestro-prod.westus2.cloudapp.azure.com/Account/Tokens - [Parameter(Mandatory=$true)][string] $gitHubPat, # GitHub personal access token from https://github.com/settings/tokens (no auth scopes needed) - [Parameter(Mandatory=$true)][string] $azdoPat, # Azure Dev Ops tokens from https://dev.azure.com/dnceng/_details/security/tokens (code read scope needed) - [Parameter(Mandatory=$true)][string] $outputFolder, # Where the graphviz.txt file will be created - [string] $darcVersion, # darc's version - [string] $graphvizVersion = '2.38', # GraphViz version - [switch] $includeToolset # Whether the graph should include toolset dependencies or not. i.e. arcade, optimization. For more about - # toolset dependencies see https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md#toolset-vs-product-dependencies -) - -function CheckExitCode ([string]$stage) -{ - $exitCode = $LASTEXITCODE - if ($exitCode -ne 0) { - Write-PipelineTelemetryError -Category 'Arcade' -Message "Something failed in stage: '$stage'. Check for errors above. Exiting now..." - ExitWithExitCode $exitCode - } -} - -try { - $ErrorActionPreference = 'Stop' - . $PSScriptRoot\tools.ps1 - - Import-Module -Name (Join-Path $PSScriptRoot 'native\CommonLibrary.psm1') - - Push-Location $PSScriptRoot - - Write-Host 'Installing darc...' - . .\darc-init.ps1 -darcVersion $darcVersion - CheckExitCode 'Running darc-init' - - $engCommonBaseDir = Join-Path $PSScriptRoot 'native\' - $graphvizInstallDir = CommonLibrary\Get-NativeInstallDirectory - $nativeToolBaseUri = 'https://netcorenativeassets.blob.core.windows.net/resource-packages/external' - $installBin = Join-Path $graphvizInstallDir 'bin' - - Write-Host 'Installing dot...' - .\native\install-tool.ps1 -ToolName graphviz -InstallPath $installBin -BaseUri $nativeToolBaseUri -CommonLibraryDirectory $engCommonBaseDir -Version $graphvizVersion -Verbose - - $darcExe = "$env:USERPROFILE\.dotnet\tools" - $darcExe = Resolve-Path "$darcExe\darc.exe" - - Create-Directory $outputFolder - - # Generate 3 graph descriptions: - # 1. Flat with coherency information - # 2. Graphviz (dot) file - # 3. Standard dependency graph - $graphVizFilePath = "$outputFolder\graphviz.txt" - $graphVizImageFilePath = "$outputFolder\graph.png" - $normalGraphFilePath = "$outputFolder\graph-full.txt" - $flatGraphFilePath = "$outputFolder\graph-flat.txt" - $baseOptions = @( '--github-pat', "$gitHubPat", '--azdev-pat', "$azdoPat", '--password', "$barToken" ) - - if ($includeToolset) { - Write-Host 'Toolsets will be included in the graph...' - $baseOptions += @( '--include-toolset' ) - } - - Write-Host 'Generating standard dependency graph...' - & "$darcExe" get-dependency-graph @baseOptions --output-file $normalGraphFilePath - CheckExitCode 'Generating normal dependency graph' - - Write-Host 'Generating flat dependency graph and graphviz file...' - & "$darcExe" get-dependency-graph @baseOptions --flat --coherency --graphviz $graphVizFilePath --output-file $flatGraphFilePath - CheckExitCode 'Generating flat and graphviz dependency graph' - - Write-Host "Generating graph image $graphVizFilePath" - $dotFilePath = Join-Path $installBin "graphviz\$graphvizVersion\release\bin\dot.exe" - & "$dotFilePath" -Tpng -o"$graphVizImageFilePath" "$graphVizFilePath" - CheckExitCode 'Generating graphviz image' - - Write-Host "'$graphVizFilePath', '$flatGraphFilePath', '$normalGraphFilePath' and '$graphVizImageFilePath' created!" -} -catch { - if (!$includeToolset) { - Write-Host 'This might be a toolset repo which includes only toolset dependencies. ' -NoNewline -ForegroundColor Yellow - Write-Host 'Since -includeToolset is not set there is no graph to create. Include -includeToolset and try again...' -ForegroundColor Yellow - } - Write-Host $_.ScriptStackTrace - Write-PipelineTelemetryError -Category 'Arcade' -Message $_ - ExitWithExitCode 1 -} finally { - Pop-Location -} \ No newline at end of file diff --git a/eng/common/internal/NuGet.config b/eng/common/internal/NuGet.config new file mode 100644 index 0000000000000..19d3d311b166f --- /dev/null +++ b/eng/common/internal/NuGet.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1 index 2427ca6b6aec7..8508397d77640 100644 --- a/eng/common/post-build/publish-using-darc.ps1 +++ b/eng/common/post-build/publish-using-darc.ps1 @@ -5,13 +5,8 @@ param( [Parameter(Mandatory=$true)][string] $MaestroToken, [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com', [Parameter(Mandatory=$true)][string] $WaitPublishingFinish, - [Parameter(Mandatory=$false)][string] $EnableSourceLinkValidation, - [Parameter(Mandatory=$false)][string] $EnableSigningValidation, - [Parameter(Mandatory=$false)][string] $EnableNugetValidation, - [Parameter(Mandatory=$false)][string] $PublishInstallersAndChecksums, [Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters, - [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters, - [Parameter(Mandatory=$false)][string] $SigningValidationAdditionalParameters + [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters ) try { @@ -35,27 +30,6 @@ try { $optionalParams.Add("--no-wait") | Out-Null } - if ("false" -ne $PublishInstallersAndChecksums) { - $optionalParams.Add("--publish-installers-and-checksums") | Out-Null - } - - if ("true" -eq $EnableNugetValidation) { - $optionalParams.Add("--validate-nuget") | Out-Null - } - - if ("true" -eq $EnableSourceLinkValidation) { - $optionalParams.Add("--validate-sourcelinkchecksums") | Out-Null - } - - if ("true" -eq $EnableSigningValidation) { - $optionalParams.Add("--validate-signingchecksums") | Out-Null - - if ("" -ne $SigningValidationAdditionalParameters) { - $optionalParams.Add("--signing-validation-parameters") | Out-Null - $optionalParams.Add($SigningValidationAdditionalParameters) | Out-Null - } - } - & $darc add-build-to-channel ` --id $buildId ` --publishing-infra-version $PublishingInfraVersion ` diff --git a/eng/common/sdl/configure-sdl-tool.ps1 b/eng/common/sdl/configure-sdl-tool.ps1 index 8a68fc24b11b0..bdbf49e6c71de 100644 --- a/eng/common/sdl/configure-sdl-tool.ps1 +++ b/eng/common/sdl/configure-sdl-tool.ps1 @@ -15,7 +15,9 @@ Param( # Optional: Additional params to add to any tool using CredScan. [string[]] $CrScanAdditionalRunConfigParams, # Optional: Additional params to add to any tool using PoliCheck. - [string[]] $PoliCheckAdditionalRunConfigParams + [string[]] $PoliCheckAdditionalRunConfigParams, + # Optional: Additional params to add to any tool using CodeQL/Semmle. + [string[]] $CodeQLAdditionalRunConfigParams ) $ErrorActionPreference = 'Stop' @@ -78,6 +80,11 @@ try { $tool.Args += "`"Target < $TargetDirectory`"" } $tool.Args += $PoliCheckAdditionalRunConfigParams + } elseif ($tool.Name -eq 'semmle' -or $tool.Name -eq 'codeql') { + if ($targetDirectory) { + $tool.Args += "`"SourceCodeDirectory < $TargetDirectory`"" + } + $tool.Args += $CodeQLAdditionalRunConfigParams } # Create variable pointing to the args array directly so we can use splat syntax later. diff --git a/eng/common/sdl/execute-all-sdl-tools.ps1 b/eng/common/sdl/execute-all-sdl-tools.ps1 index e5bef8ebd3a3b..4797e012c7d2f 100644 --- a/eng/common/sdl/execute-all-sdl-tools.ps1 +++ b/eng/common/sdl/execute-all-sdl-tools.ps1 @@ -34,6 +34,7 @@ Param( [string] $GuardianLoggerLevel='Standard', # Optional: the logger level for the Guardian CLI; options are Trace, Verbose, Standard, Warning, and Error [string[]] $CrScanAdditionalRunConfigParams, # Optional: Additional Params to custom build a CredScan run config in the format @("xyz:abc","sdf:1") [string[]] $PoliCheckAdditionalRunConfigParams, # Optional: Additional Params to custom build a Policheck run config in the format @("xyz:abc","sdf:1") + [string[]] $CodeQLAdditionalRunConfigParams, # Optional: Additional Params to custom build a Semmle/CodeQL run config in the format @("xyz < abc","sdf < 1") [bool] $BreakOnFailure=$False # Optional: Fail the build if there were errors during the run ) @@ -105,7 +106,8 @@ try { -AzureDevOpsAccessToken $AzureDevOpsAccessToken ` -GuardianLoggerLevel $GuardianLoggerLevel ` -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams ` - -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams + -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams ` + -CodeQLAdditionalRunConfigParams $CodeQLAdditionalRunConfigParams if ($BreakOnFailure) { Exit-IfNZEC "Sdl" } diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml index 8cf772b3cbf81..24cec0424e5d6 100644 --- a/eng/common/templates/job/execute-sdl.yml +++ b/eng/common/templates/job/execute-sdl.yml @@ -29,14 +29,6 @@ parameters: # Optional: download a list of pipeline artifacts. 'downloadArtifacts' controls build artifacts, # not pipeline artifacts, so doesn't affect the use of this parameter. pipelineArtifactNames: [] - # Optional: location and ID of the AzDO build that the build/pipeline artifacts should be - # downloaded from. By default, uses runtime expressions to decide based on the variables set by - # the 'setupMaestroVars' dependency. Overriding this parameter is necessary if SDL tasks are - # running without Maestro++/BAR involved, or to download artifacts from a specific existing build - # to iterate quickly on SDL changes. - AzDOProjectName: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - AzDOPipelineId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - AzDOBuildId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] jobs: - job: Run_SDL @@ -55,11 +47,20 @@ jobs: - name: GuardianVersion value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} pool: - vmImage: windows-2019 + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - checkout: self clean: true + - template: /eng/common/templates/post-build/setup-maestro-vars.yml + - ${{ if ne(parameters.downloadArtifacts, 'false')}}: - ${{ if ne(parameters.artifactNames, '') }}: - ${{ each artifactName in parameters.artifactNames }}: diff --git a/eng/common/templates/job/generate-graph-files.yml b/eng/common/templates/job/generate-graph-files.yml deleted file mode 100644 index e54ce956f9088..0000000000000 --- a/eng/common/templates/job/generate-graph-files.yml +++ /dev/null @@ -1,48 +0,0 @@ -parameters: - # Optional: dependencies of the job - dependsOn: '' - - # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool - pool: {} - - # Optional: Include toolset dependencies in the generated graph files - includeToolset: false - -jobs: -- job: Generate_Graph_Files - - dependsOn: ${{ parameters.dependsOn }} - - displayName: Generate Graph Files - - pool: ${{ parameters.pool }} - - variables: - # Publish-Build-Assets provides: MaestroAccessToken, BotAccount-dotnet-maestro-bot-PAT - # DotNet-AllOrgs-Darc-Pats provides: dn-bot-devdiv-dnceng-rw-code-pat - - group: Publish-Build-Assets - - group: DotNet-AllOrgs-Darc-Pats - - name: _GraphArguments - value: -gitHubPat $(BotAccount-dotnet-maestro-bot-PAT) - -azdoPat $(dn-bot-devdiv-dnceng-rw-code-pat) - -barToken $(MaestroAccessToken) - -outputFolder '$(Build.StagingDirectory)/GraphFiles/' - - ${{ if ne(parameters.includeToolset, 'false') }}: - - name: _GraphArguments - value: ${{ variables._GraphArguments }} -includeToolset - - steps: - - task: PowerShell@2 - displayName: Generate Graph Files - inputs: - filePath: eng\common\generate-graph-files.ps1 - arguments: $(_GraphArguments) - continueOnError: true - - task: PublishBuildArtifacts@1 - displayName: Publish Graph to Artifacts - inputs: - PathtoPublish: '$(Build.StagingDirectory)/GraphFiles' - PublishLocation: Container - ArtifactName: GraphFiles - continueOnError: true - condition: always() diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml index 7678b94ce740c..c5c2a9915121b 100644 --- a/eng/common/templates/job/job.yml +++ b/eng/common/templates/job/job.yml @@ -24,6 +24,7 @@ parameters: enablePublishBuildAssets: false enablePublishTestResults: false enablePublishUsingPipelines: false + disableComponentGovernance: false mergeTestResults: false testRunTitle: '' testResultsFormat: '' @@ -137,6 +138,9 @@ jobs: richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin continueOnError: true + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), ne(parameters.disableComponentGovernance, 'true')) }}: + - task: ComponentGovernanceComponentDetection@0 + - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - task: MicroBuildCleanup@1 diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index c4fc18b3ee77a..9d1e3042d8a6c 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -3,9 +3,8 @@ parameters: dependsOn: '' # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool - pool: - vmImage: 'windows-2019' - + pool: '' + CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex GithubPat: $(BotAccount-dotnet-bot-repo-PAT) @@ -31,7 +30,18 @@ jobs: displayName: OneLocBuild - pool: ${{ parameters.pool }} + ${{ if ne(parameters.pool, '') }}: + pool: ${{ parameters.pool }} + ${{ if eq(parameters.pool, '') }}: + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 variables: - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml index fe9dfdf720cf8..d91bf9147116f 100644 --- a/eng/common/templates/job/publish-build-assets.yml +++ b/eng/common/templates/job/publish-build-assets.yml @@ -38,10 +38,6 @@ jobs: value: ${{ parameters.configuration }} - group: Publish-Build-Assets - group: AzureDevOps-Artifact-Feeds-Pats - # Skip component governance and codesign validation for SDL. These jobs - # create no content. - - name: skipComponentGovernanceDetection - value: true - name: runCodesignValidationInjection value: false diff --git a/eng/common/templates/jobs/codeql-build.yml b/eng/common/templates/jobs/codeql-build.yml new file mode 100644 index 0000000000000..f7dc5ea4aaa63 --- /dev/null +++ b/eng/common/templates/jobs/codeql-build.yml @@ -0,0 +1,31 @@ +parameters: + # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md + continueOnError: false + # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job + jobs: [] + # Optional: if specified, restore and use this version of Guardian instead of the default. + overrideGuardianVersion: '' + +jobs: +- template: /eng/common/templates/jobs/jobs.yml + parameters: + enableMicrobuild: false + enablePublishBuildArtifacts: false + enablePublishTestResults: false + enablePublishBuildAssets: false + enablePublishUsingPipelines: false + enableTelemetry: true + + variables: + - group: Publish-Build-Assets + # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in + # sync with the packages.config file. + - name: DefaultGuardianVersion + value: 0.109.0 + - name: GuardianPackagesConfigFile + value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config + - name: GuardianVersion + value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} + + jobs: ${{ parameters.jobs }} + diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml index 8dd1fdbd144a0..70d44735ace4a 100644 --- a/eng/common/templates/jobs/jobs.yml +++ b/eng/common/templates/jobs/jobs.yml @@ -8,6 +8,10 @@ parameters: # Optional: Enable publishing using release pipelines enablePublishUsingPipelines: false + # Optional: Disable component governance detection. In general, component governance + # should be on for all jobs. Use only in the event of issues. + disableComponentGovernance: false + # Optional: Enable running the source-build jobs to build repo from source enableSourceBuild: false @@ -83,17 +87,15 @@ jobs: - ${{ if eq(parameters.enableSourceBuild, true) }}: - Source_Build_Complete pool: - vmImage: 'windows-2019' + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 + runAsPublic: ${{ parameters.runAsPublic }} publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} - - - ${{ if eq(parameters.graphFileGeneration.enabled, true) }}: - - template: ../job/generate-graph-files.yml - parameters: - continueOnError: ${{ parameters.continueOnError }} - includeToolset: ${{ parameters.graphFileGeneration.includeToolset }} - dependsOn: - - Asset_Registry_Publish - pool: - vmImage: 'windows-2019' diff --git a/eng/common/templates/post-build/channels/generic-internal-channel.yml b/eng/common/templates/post-build/channels/generic-internal-channel.yml deleted file mode 100644 index 8990dfc8c87cc..0000000000000 --- a/eng/common/templates/post-build/channels/generic-internal-channel.yml +++ /dev/null @@ -1,190 +0,0 @@ -parameters: - BARBuildId: '' - PromoteToChannelIds: '' - artifactsPublishingAdditionalParameters: '' - dependsOn: - - Validate - publishInstallersAndChecksums: true - symbolPublishingAdditionalParameters: '' - stageName: '' - channelName: '' - channelId: '' - transportFeed: '' - shippingFeed: '' - symbolsFeed: '' - -stages: -- stage: ${{ parameters.stageName }} - dependsOn: ${{ parameters.dependsOn }} - variables: - - template: ../common-variables.yml - displayName: ${{ parameters.channelName }} Publishing - jobs: - - template: ../setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - job: publish_symbols - displayName: Symbol Publishing - dependsOn: setupMaestroVars - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) - variables: - - group: DotNet-Symbol-Server-Pats - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - pool: - vmImage: 'windows-2019' - steps: - - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." - displayName: Warn about v2 Arcade Publishing Usage - - # This is necessary whenever we want to publish/restore to an AzDO private feed - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: DownloadBuildArtifacts@0 - displayName: Download Build Assets - continueOnError: true - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: 'specific' - itemPattern: | - PdbArtifacts/** - BlobArtifacts/** - downloadPath: '$(Build.ArtifactStagingDirectory)' - checkDownloadedFiles: true - - # This is necessary whenever we want to publish/restore to an AzDO private feed - # Since sdk-task.ps1 tries to restore packages we need to do this authentication here - # otherwise it'll complain about accessing a private feed. - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: PowerShell@2 - displayName: Enable cross-org publishing - inputs: - filePath: eng\common\enable-cross-org-publishing.ps1 - arguments: -token $(dn-bot-dnceng-artifact-feeds-rw) - - - task: PowerShell@2 - displayName: Publish - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet - /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat) - /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat) - /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/' - /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' - /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' - /p:Configuration=Release - /p:PublishToMSDL=false - ${{ parameters.symbolPublishingAdditionalParameters }} - - - template: ../../steps/publish-logs.yml - parameters: - StageLabel: '${{ parameters.stageName }}' - JobLabel: 'SymbolPublishing' - - - job: publish_assets - displayName: Publish Assets - dependsOn: setupMaestroVars - timeoutInMinutes: 120 - variables: - - name: BARBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - - name: IsStableBuild - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ] - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) - pool: - vmImage: 'windows-2019' - steps: - - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." - displayName: Warn about v2 Arcade Publishing Usage - - - task: DownloadBuildArtifacts@0 - displayName: Download Build Assets - continueOnError: true - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: 'specific' - itemPattern: | - PackageArtifacts/** - BlobArtifacts/** - AssetManifests/** - downloadPath: '$(Build.ArtifactStagingDirectory)' - checkDownloadedFiles: true - - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - - # This is necessary whenever we want to publish/restore to an AzDO private feed - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: PowerShell@2 - displayName: Enable cross-org publishing - inputs: - filePath: eng\common\enable-cross-org-publishing.ps1 - arguments: -token $(dn-bot-dnceng-artifact-feeds-rw) - - - task: PowerShell@2 - displayName: Publish Assets - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet - /p:PublishingInfraVersion=2 - /p:IsStableBuild=$(IsStableBuild) - /p:IsInternalBuild=$(IsInternalBuild) - /p:RepositoryName=$(Build.Repository.Name) - /p:CommitSha=$(Build.SourceVersion) - /p:NugetPath=$(NuGetExeToolPath) - /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-universal-packages-rw)' - /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' - /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' - /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' - /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' - /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' - /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/' - /p:Configuration=Release - /p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }} - /p:ChecksumsTargetStaticFeed=$(InternalChecksumsBlobFeedUrl) - /p:ChecksumsAzureAccountKey=$(InternalChecksumsBlobFeedKey) - /p:InstallersTargetStaticFeed=$(InternalInstallersBlobFeedUrl) - /p:InstallersAzureAccountKey=$(InternalInstallersBlobFeedKey) - /p:AzureDevOpsStaticShippingFeed='${{ parameters.shippingFeed }}' - /p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:AzureDevOpsStaticTransportFeed='${{ parameters.transportFeed }}' - /p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:AzureDevOpsStaticSymbolsFeed='${{ parameters.symbolsFeed }}' - /p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:PublishToMSDL=false - ${{ parameters.artifactsPublishingAdditionalParameters }} - - - template: ../../steps/publish-logs.yml - parameters: - StageLabel: '${{ parameters.stageName }}' - JobLabel: 'AssetsPublishing' - - - template: ../../steps/add-build-to-channel.yml - parameters: - ChannelId: ${{ parameters.channelId }} diff --git a/eng/common/templates/post-build/channels/generic-public-channel.yml b/eng/common/templates/post-build/channels/generic-public-channel.yml deleted file mode 100644 index 3220c6a4f92ff..0000000000000 --- a/eng/common/templates/post-build/channels/generic-public-channel.yml +++ /dev/null @@ -1,192 +0,0 @@ -parameters: - BARBuildId: '' - PromoteToChannelIds: '' - artifactsPublishingAdditionalParameters: '' - dependsOn: - - Validate - publishInstallersAndChecksums: true - symbolPublishingAdditionalParameters: '' - stageName: '' - channelName: '' - channelId: '' - transportFeed: '' - shippingFeed: '' - symbolsFeed: '' - # If the channel name is empty, no links will be generated - akaMSChannelName: '' - -stages: -- stage: ${{ parameters.stageName }} - dependsOn: ${{ parameters.dependsOn }} - variables: - - template: ../common-variables.yml - displayName: ${{ parameters.channelName }} Publishing - jobs: - - template: ../setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - job: publish_symbols - displayName: Symbol Publishing - dependsOn: setupMaestroVars - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) - variables: - - group: DotNet-Symbol-Server-Pats - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - pool: - vmImage: 'windows-2019' - steps: - - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." - displayName: Warn about v2 Arcade Publishing Usage - - - task: DownloadBuildArtifacts@0 - displayName: Download Build Assets - continueOnError: true - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: 'specific' - itemPattern: | - PdbArtifacts/** - BlobArtifacts/** - downloadPath: '$(Build.ArtifactStagingDirectory)' - checkDownloadedFiles: true - - # This is necessary whenever we want to publish/restore to an AzDO private feed - # Since sdk-task.ps1 tries to restore packages we need to do this authentication here - # otherwise it'll complain about accessing a private feed. - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: PowerShell@2 - displayName: Enable cross-org publishing - inputs: - filePath: eng\common\enable-cross-org-publishing.ps1 - arguments: -token $(dn-bot-dnceng-artifact-feeds-rw) - - - task: PowerShell@2 - displayName: Publish - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet - /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat) - /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat) - /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/' - /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' - /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' - /p:Configuration=Release - ${{ parameters.symbolPublishingAdditionalParameters }} - - - template: ../../steps/publish-logs.yml - parameters: - StageLabel: '${{ parameters.stageName }}' - JobLabel: 'SymbolPublishing' - - - job: publish_assets - displayName: Publish Assets - dependsOn: setupMaestroVars - timeoutInMinutes: 120 - variables: - - name: BARBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - - name: IsStableBuild - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ] - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - - name: ArtifactsCategory - value: ${{ coalesce(variables._DotNetArtifactsCategory, '.NETCore') }} - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) - pool: - vmImage: 'windows-2019' - steps: - - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions." - displayName: Warn about v2 Arcade Publishing Usage - - - task: DownloadBuildArtifacts@0 - displayName: Download Build Assets - continueOnError: true - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: 'specific' - itemPattern: | - PackageArtifacts/** - BlobArtifacts/** - AssetManifests/** - downloadPath: '$(Build.ArtifactStagingDirectory)' - checkDownloadedFiles: true - - - task: NuGetToolInstaller@1 - displayName: 'Install NuGet.exe' - - # This is necessary whenever we want to publish/restore to an AzDO private feed - - task: NuGetAuthenticate@0 - displayName: 'Authenticate to AzDO Feeds' - - - task: PowerShell@2 - displayName: Enable cross-org publishing - inputs: - filePath: eng\common\enable-cross-org-publishing.ps1 - arguments: -token $(dn-bot-dnceng-artifact-feeds-rw) - - - task: PowerShell@2 - displayName: Publish Assets - inputs: - filePath: eng\common\sdk-task.ps1 - arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet - /p:PublishingInfraVersion=2 - /p:ArtifactsCategory=$(ArtifactsCategory) - /p:IsStableBuild=$(IsStableBuild) - /p:IsInternalBuild=$(IsInternalBuild) - /p:RepositoryName=$(Build.Repository.Name) - /p:CommitSha=$(Build.SourceVersion) - /p:NugetPath=$(NuGetExeToolPath) - /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-universal-packages-rw)' - /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' - /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' - /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' - /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' - /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' - /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/' - /p:Configuration=Release - /p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }} - /p:InstallersTargetStaticFeed=$(InstallersBlobFeedUrl) - /p:InstallersAzureAccountKey=$(dotnetcli-storage-key) - /p:ChecksumsTargetStaticFeed=$(ChecksumsBlobFeedUrl) - /p:ChecksumsAzureAccountKey=$(dotnetclichecksums-storage-key) - /p:AzureDevOpsStaticShippingFeed='${{ parameters.shippingFeed }}' - /p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:AzureDevOpsStaticTransportFeed='${{ parameters.transportFeed }}' - /p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:AzureDevOpsStaticSymbolsFeed='${{ parameters.symbolsFeed }}' - /p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)' - /p:LatestLinkShortUrlPrefix=dotnet/'${{ parameters.akaMSChannelName }}' - /p:AkaMSClientId=$(akams-client-id) - /p:AkaMSClientSecret=$(akams-client-secret) - ${{ parameters.artifactsPublishingAdditionalParameters }} - - - template: ../../steps/publish-logs.yml - parameters: - StageLabel: '${{ parameters.stageName }}' - JobLabel: 'AssetsPublishing' - - - template: ../../steps/add-build-to-channel.yml - parameters: - ChannelId: ${{ parameters.channelId }} diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml index c99fd7503767c..1ac7f49a43ca8 100644 --- a/eng/common/templates/post-build/common-variables.yml +++ b/eng/common/templates/post-build/common-variables.yml @@ -4,54 +4,6 @@ variables: - group: DotNet-DotNetCli-Storage - group: DotNet-MSRC-Storage - group: Publish-Build-Assets - - # .NET Core 3.1 Dev - - name: PublicDevRelease_31_Channel_Id - value: 128 - - # .NET 5 Dev - - name: Net_5_Dev_Channel_Id - value: 131 - - # .NET Eng - Validation - - name: Net_Eng_Validation_Channel_Id - value: 9 - - # .NET Eng - Latest - - name: Net_Eng_Latest_Channel_Id - value: 2 - - # .NET 3 Eng - Validation - - name: NET_3_Eng_Validation_Channel_Id - value: 390 - - # .NET 3 Eng - - name: NetCore_3_Tools_Channel_Id - value: 344 - - # .NET Core 3.0 Internal Servicing - - name: InternalServicing_30_Channel_Id - value: 184 - - # .NET Core 3.0 Release - - name: PublicRelease_30_Channel_Id - value: 19 - - # .NET Core 3.1 Release - - name: PublicRelease_31_Channel_Id - value: 129 - - # General Testing - - name: GeneralTesting_Channel_Id - value: 529 - - # .NET Core 3.1 Blazor Features - - name: NetCore_31_Blazor_Features_Channel_Id - value: 531 - - # .NET Core Experimental - - name: NetCore_Experimental_Channel_Id - value: 562 # Whether the build is internal or not - name: IsInternalBuild @@ -70,30 +22,5 @@ variables: - name: SymbolToolVersion value: 1.0.1 - # Feed Configurations - # These should include the suffix "/index.json" - - # Default locations for Installers and checksums - # Public Locations - - name: ChecksumsBlobFeedUrl - value: https://dotnetclichecksums.blob.core.windows.net/dotnet/index.json - - name: InstallersBlobFeedUrl - value: https://dotnetcli.blob.core.windows.net/dotnet/index.json - - # Private Locations - - name: InternalChecksumsBlobFeedUrl - value: https://dotnetclichecksumsmsrc.blob.core.windows.net/dotnet/index.json - - name: InternalChecksumsBlobFeedKey - value: $(dotnetclichecksumsmsrc-storage-key) - - - name: InternalInstallersBlobFeedUrl - value: https://dotnetclimsrc.blob.core.windows.net/dotnet/index.json - - name: InternalInstallersBlobFeedKey - value: $(dotnetclimsrc-access-key) - - # Skip component governance and codesign validation for SDL. These jobs - # create no content. - - name: skipComponentGovernanceDetection - value: true - name: runCodesignValidationInjection value: false diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index 4f79cf0f33703..2f176571f020c 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -1,113 +1,114 @@ parameters: - # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST. - # Publishing V2 accepts optionally outlining the publishing stages - default is inline. - # Publishing V3 DOES NOT accept inlining the publishing stages. - publishingInfraVersion: 2 - # When set to true the publishing templates from the repo will be used - # otherwise Darc add-build-to-channel will be used to trigger the promotion pipeline - inline: true - - # Only used if inline==false. When set to true will stall the current build until - # the Promotion Pipeline build finishes. Otherwise, the current build will continue - # execution concurrently with the promotion build. - waitPublishingFinish: true - - BARBuildId: '' - PromoteToChannelIds: '' - - enableSourceLinkValidation: false - enableSigningValidation: true - enableSymbolValidation: false - enableNugetValidation: true - publishInstallersAndChecksums: true - SDLValidationParameters: - enable: false - continueOnError: false - params: '' - artifactNames: '' - downloadArtifacts: true + # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST. + # Publishing V1 is no longer supported + # Publishing V2 is no longer supported + # Publishing V3 is the default + - name: publishingInfraVersion + displayName: Which version of publishing should be used to promote the build definition? + type: number + default: 3 + values: + - 3 + + - name: BARBuildId + displayName: BAR Build Id + type: number + default: 0 + + - name: PromoteToChannelIds + displayName: Channel to promote BARBuildId to + type: string + default: '' + + - name: enableSourceLinkValidation + displayName: Enable SourceLink validation + type: boolean + default: false + + - name: enableSigningValidation + displayName: Enable signing validation + type: boolean + default: true + + - name: enableSymbolValidation + displayName: Enable symbol validation + type: boolean + default: false + + - name: enableNugetValidation + displayName: Enable NuGet validation + type: boolean + default: true + + - name: publishInstallersAndChecksums + displayName: Publish installers and checksums + type: boolean + default: true + + - name: SDLValidationParameters + type: object + default: + enable: false + continueOnError: false + params: '' + artifactNames: '' + downloadArtifacts: true # These parameters let the user customize the call to sdk-task.ps1 for publishing # symbols & general artifacts as well as for signing validation - symbolPublishingAdditionalParameters: '' - artifactsPublishingAdditionalParameters: '' - signingValidationAdditionalParameters: '' + - name: symbolPublishingAdditionalParameters + displayName: Symbol publishing additional parameters + type: string + default: '' + + - name: artifactsPublishingAdditionalParameters + displayName: Artifact publishing additional parameters + type: string + default: '' + + - name: signingValidationAdditionalParameters + displayName: Signing validation additional parameters + type: string + default: '' # Which stages should finish execution before post-build stages start - validateDependsOn: - - build - publishDependsOn: - - Validate + - name: validateDependsOn + type: object + default: + - build - # Channel ID's instantiated in this file. - # When adding a new channel implementation the call to `check-channel-consistency.ps1` - # needs to be updated with the new channel ID - NetEngLatestChannelId: 2 - NetEngValidationChannelId: 9 - NetDev5ChannelId: 131 - NetDev6ChannelId: 1296 - GeneralTestingChannelId: 529 - NETCoreToolingDevChannelId: 548 - NETCoreToolingReleaseChannelId: 549 - NETInternalToolingChannelId: 551 - NETCoreExperimentalChannelId: 562 - NetEngServicesIntChannelId: 678 - NetEngServicesProdChannelId: 679 - NetCoreSDK313xxChannelId: 759 - NetCoreSDK313xxInternalChannelId: 760 - NetCoreSDK314xxChannelId: 921 - NetCoreSDK314xxInternalChannelId: 922 - VS166ChannelId: 1010 - VS167ChannelId: 1011 - VS168ChannelId: 1154 - VSMasterChannelId: 1012 - VS169ChannelId: 1473 - VS1610ChannelId: 1692 + - name: publishDependsOn + type: object + default: + - Validate stages: -- ${{ if or(and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')), eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: +- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - stage: Validate dependsOn: ${{ parameters.validateDependsOn }} displayName: Validate Build Assets variables: - template: common-variables.yml jobs: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - ${{ if and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')) }}: - - job: - displayName: Post-build Checks - dependsOn: setupMaestroVars - variables: - - name: TargetChannels - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'] ] - pool: - vmImage: 'windows-2019' - steps: - - task: PowerShell@2 - displayName: Maestro Channels Consistency - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/check-channel-consistency.ps1 - arguments: -PromoteToChannels "$(TargetChannels)" - -AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.NetDev6ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.NetCoreSDK313xxChannelId}},${{parameters.NetCoreSDK313xxInternalChannelId}},${{parameters.NetCoreSDK314xxChannelId}},${{parameters.NetCoreSDK314xxInternalChannelId}},${{parameters.VS166ChannelId}},${{parameters.VS167ChannelId}},${{parameters.VS168ChannelId}},${{parameters.VSMasterChannelId}},${{parameters.VS169ChannelId}},${{parameters.VS1610ChannelId}} - - job: displayName: NuGet Validation - dependsOn: setupMaestroVars condition: eq( ${{ parameters.enableNugetValidation }}, 'true') pool: - vmImage: 'windows-2019' - variables: - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 + steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + - task: DownloadBuildArtifacts@0 displayName: Download Package Artifacts inputs: @@ -128,19 +129,22 @@ stages: - job: displayName: Signing Validation - dependsOn: setupMaestroVars condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true')) - variables: - - template: common-variables.yml - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] pool: - vmImage: 'windows-2019' + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + - task: DownloadBuildArtifacts@0 displayName: Download Package Artifacts inputs: @@ -185,19 +189,22 @@ stages: - job: displayName: SourceLink Validation - dependsOn: setupMaestroVars condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true') - variables: - - template: common-variables.yml - - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] - - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] pool: - vmImage: 'windows-2019' + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + - task: DownloadBuildArtifacts@0 displayName: Download Blob Artifacts inputs: @@ -223,367 +230,48 @@ stages: - template: /eng/common/templates/job/execute-sdl.yml parameters: enable: ${{ parameters.SDLValidationParameters.enable }} - dependsOn: setupMaestroVars additionalParameters: ${{ parameters.SDLValidationParameters.params }} continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }} artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }} downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }} -- ${{ if or(ge(parameters.publishingInfraVersion, 3), eq(parameters.inline, 'false')) }}: - - stage: publish_using_darc - ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: - dependsOn: ${{ parameters.publishDependsOn }} - ${{ if and(ne(parameters.enableNugetValidation, 'true'), ne(parameters.enableSigningValidation, 'true'), ne(parameters.enableSourceLinkValidation, 'true'), ne(parameters.SDLValidationParameters.enable, 'true')) }}: - dependsOn: ${{ parameters.validateDependsOn }} - displayName: Publish using Darc - variables: - - template: common-variables.yml - jobs: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - - job: - displayName: Publish Using Darc - dependsOn: setupMaestroVars - timeoutInMinutes: 120 - variables: - - name: BARBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - pool: - vmImage: 'windows-2019' - steps: - - task: PowerShell@2 - displayName: Publish Using Darc - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) - -PublishingInfraVersion ${{ parameters.PublishingInfraVersion }} - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' - -MaestroToken '$(MaestroApiAccessToken)' - -WaitPublishingFinish ${{ parameters.waitPublishingFinish }} - -PublishInstallersAndChecksums ${{ parameters.publishInstallersAndChecksums }} - -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' - -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' - -- ${{ if and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')) }}: - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NetCore_Dev5_Publish' - channelName: '.NET 5 Dev' - akaMSChannelName: 'net5/dev' - channelId: ${{ parameters.NetDev5ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NetCore_Dev6_Publish' - channelName: '.NET 6 Dev' - akaMSChannelName: 'net6/dev' - channelId: ${{ parameters.NetDev6ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net_Eng_Latest_Publish' - channelName: '.NET Eng - Latest' - akaMSChannelName: 'eng/daily' - channelId: ${{ parameters.NetEngLatestChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net_Eng_Validation_Publish' - channelName: '.NET Eng - Validation' - akaMSChannelName: 'eng/validation' - channelId: ${{ parameters.NetEngValidationChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'General_Testing_Publish' - channelName: 'General Testing' - akaMSChannelName: 'generaltesting' - channelId: ${{ parameters.GeneralTestingChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_Tooling_Dev_Publishing' - channelName: '.NET Core Tooling Dev' - channelId: ${{ parameters.NETCoreToolingDevChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_Tooling_Release_Publishing' - channelName: '.NET Core Tooling Release' - channelId: ${{ parameters.NETCoreToolingReleaseChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NET_Internal_Tooling_Publishing' - channelName: '.NET Internal Tooling' - channelId: ${{ parameters.NETInternalToolingChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_Experimental_Publishing' - channelName: '.NET Core Experimental' - channelId: ${{ parameters.NETCoreExperimentalChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net_Eng_Services_Int_Publish' - channelName: '.NET Eng Services - Int' - channelId: ${{ parameters.NetEngServicesIntChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net_Eng_Services_Prod_Publish' - channelName: '.NET Eng Services - Prod' - channelId: ${{ parameters.NetEngServicesProdChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_SDK_314xx_Publishing' - channelName: '.NET Core SDK 3.1.4xx' - channelId: ${{ parameters.NetCoreSDK314xxChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_SDK_314xx_Internal_Publishing' - channelName: '.NET Core SDK 3.1.4xx Internal' - channelId: ${{ parameters.NetCoreSDK314xxInternalChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_SDK_313xx_Publishing' - channelName: '.NET Core SDK 3.1.3xx' - channelId: ${{ parameters.NetCoreSDK313xxChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'NETCore_SDK_313xx_Internal_Publishing' - channelName: '.NET Core SDK 3.1.3xx Internal' - channelId: ${{ parameters.NetCoreSDK313xxInternalChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS16_6_Publishing' - channelName: 'VS 16.6' - channelId: ${{ parameters.VS166ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS16_7_Publishing' - channelName: 'VS 16.7' - channelId: ${{ parameters.VS167ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS16_8_Publishing' - channelName: 'VS 16.8' - channelId: ${{ parameters.VS168ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS_Master_Publishing' - channelName: 'VS Master' - channelId: ${{ parameters.VSMasterChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS_16_9_Publishing' - channelName: 'VS 16.9' - channelId: ${{ parameters.VS169ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' - - - template: \eng\common\templates\post-build\channels\generic-public-channel.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} - dependsOn: ${{ parameters.publishDependsOn }} - publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} - symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'VS_16_10_Publishing' - channelName: 'VS 16.10' - channelId: ${{ parameters.VS1610ChannelId }} - transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json' - shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' - symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json' +- stage: publish_using_darc + ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}: + dependsOn: ${{ parameters.publishDependsOn }} + ${{ if and(ne(parameters.enableNugetValidation, 'true'), ne(parameters.enableSigningValidation, 'true'), ne(parameters.enableSourceLinkValidation, 'true'), ne(parameters.SDLValidationParameters.enable, 'true')) }}: + dependsOn: ${{ parameters.validateDependsOn }} + displayName: Publish using Darc + variables: + - template: common-variables.yml + jobs: + - job: + displayName: Publish Using Darc + timeoutInMinutes: 120 + pool: + # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com) + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + name: VSEngSS-MicroBuild2022-1ES + demands: Cmd + # If it's not devdiv, it's dnceng + ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 + steps: + - template: setup-maestro-vars.yml + parameters: + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} + + - task: NuGetAuthenticate@0 + + - task: PowerShell@2 + displayName: Publish Using Darc + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 + arguments: -BuildId $(BARBuildId) + -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} + -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -MaestroToken '$(MaestroApiAccessToken)' + -WaitPublishingFinish true + -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' + -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' \ No newline at end of file diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml index 4a22b2e6f6de7..0c87f149a4ad7 100644 --- a/eng/common/templates/post-build/setup-maestro-vars.yml +++ b/eng/common/templates/post-build/setup-maestro-vars.yml @@ -2,77 +2,69 @@ parameters: BARBuildId: '' PromoteToChannelIds: '' -jobs: -- job: setupMaestroVars - displayName: Setup Maestro Vars - variables: - - template: common-variables.yml - pool: - vmImage: 'windows-2019' - steps: - - checkout: none - - - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Release Configs - inputs: - buildType: current - artifactName: ReleaseConfigs - checkDownloadedFiles: true - - - task: PowerShell@2 - name: setReleaseVars - displayName: Set Release Configs Vars +steps: + - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}: + - task: DownloadBuildArtifacts@0 + displayName: Download Release Configs inputs: - targetType: inline - script: | - try { - if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { - $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt + buildType: current + artifactName: ReleaseConfigs + checkDownloadedFiles: true - $BarId = $Content | Select -Index 0 - $Channels = $Content | Select -Index 1 - $IsStableBuild = $Content | Select -Index 2 + - task: PowerShell@2 + name: setReleaseVars + displayName: Set Release Configs Vars + inputs: + targetType: inline + pwsh: true + script: | + try { + if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') { + $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt - $AzureDevOpsProject = $Env:System_TeamProject - $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId - $AzureDevOpsBuildId = $Env:Build_BuildId - } - else { - $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" + $BarId = $Content | Select -Index 0 + $Channels = $Content | Select -Index 1 + $IsStableBuild = $Content | Select -Index 2 - $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $apiHeaders.Add('Accept', 'application/json') - $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") - - $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } - - $BarId = $Env:BARBuildId - $Channels = $Env:PromoteToMaestroChannels -split "," - $Channels = $Channels -join "][" - $Channels = "[$Channels]" + $AzureDevOpsProject = $Env:System_TeamProject + $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId + $AzureDevOpsBuildId = $Env:Build_BuildId + } + else { + $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" - $IsStableBuild = $buildInfo.stable - $AzureDevOpsProject = $buildInfo.azureDevOpsProject - $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId - $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId - } + $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' + $apiHeaders.Add('Accept', 'application/json') + $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}") - Write-Host "##vso[task.setvariable variable=BARBuildId;isOutput=true]$BarId" - Write-Host "##vso[task.setvariable variable=TargetChannels;isOutput=true]$Channels" - Write-Host "##vso[task.setvariable variable=IsStableBuild;isOutput=true]$IsStableBuild" + $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + + $BarId = $Env:BARBuildId + $Channels = $Env:PromoteToMaestroChannels -split "," + $Channels = $Channels -join "][" + $Channels = "[$Channels]" - Write-Host "##vso[task.setvariable variable=AzDOProjectName;isOutput=true]$AzureDevOpsProject" - Write-Host "##vso[task.setvariable variable=AzDOPipelineId;isOutput=true]$AzureDevOpsBuildDefinitionId" - Write-Host "##vso[task.setvariable variable=AzDOBuildId;isOutput=true]$AzureDevOpsBuildId" + $IsStableBuild = $buildInfo.stable + $AzureDevOpsProject = $buildInfo.azureDevOpsProject + $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId + $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId } - catch { - Write-Host $_ - Write-Host $_.Exception - Write-Host $_.ScriptStackTrace - exit 1 - } - env: - MAESTRO_API_TOKEN: $(MaestroApiAccessToken) - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} + + Write-Host "##vso[task.setvariable variable=BARBuildId]$BarId" + Write-Host "##vso[task.setvariable variable=TargetChannels]$Channels" + Write-Host "##vso[task.setvariable variable=IsStableBuild]$IsStableBuild" + + Write-Host "##vso[task.setvariable variable=AzDOProjectName]$AzureDevOpsProject" + Write-Host "##vso[task.setvariable variable=AzDOPipelineId]$AzureDevOpsBuildDefinitionId" + Write-Host "##vso[task.setvariable variable=AzDOBuildId]$AzureDevOpsBuildId" + } + catch { + Write-Host $_ + Write-Host $_.Exception + Write-Host $_.ScriptStackTrace + exit 1 + } + env: + MAESTRO_API_TOKEN: $(MaestroApiAccessToken) + BARBuildId: ${{ parameters.BARBuildId }} + PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }} diff --git a/eng/common/templates/steps/execute-codeql.yml b/eng/common/templates/steps/execute-codeql.yml new file mode 100644 index 0000000000000..3930b1630214b --- /dev/null +++ b/eng/common/templates/steps/execute-codeql.yml @@ -0,0 +1,32 @@ +parameters: + # Language that should be analyzed. Defaults to csharp + language: csharp + # Build Commands + buildCommands: '' + overrideParameters: '' # Optional: to override values for parameters. + additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")' + # Optional: if specified, restore and use this version of Guardian instead of the default. + overrideGuardianVersion: '' + # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth + # diagnosis of problems with specific tool configurations. + publishGuardianDirectoryToPipeline: false + # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL + # parameters rather than relying on YAML. It may be better to use a local script, because you can + # reproduce results locally without piecing together a command based on the YAML. + executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1' + # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named + # 'continueOnError', the parameter value is not correctly picked up. + # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter + # optional: determines whether to continue the build if the step errors; + sdlContinueOnError: false + +steps: +- template: /eng/common/templates/steps/execute-sdl.yml + parameters: + overrideGuardianVersion: ${{ parameters.overrideGuardianVersion }} + executeAllSdlToolsScript: ${{ parameters.executeAllSdlToolsScript }} + overrideParameters: ${{ parameters.overrideParameters }} + additionalParameters: '${{ parameters.additionalParameters }} + -CodeQLAdditionalRunConfigParams @("BuildCommands < ${{ parameters.buildCommands }}", "Language < ${{ parameters.language }}")' + publishGuardianDirectoryToPipeline: ${{ parameters.publishGuardianDirectoryToPipeline }} + sdlContinueOnError: ${{ parameters.sdlContinueOnError }} \ No newline at end of file diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml index ba40dc82f1411..d85d6d07d5c7b 100644 --- a/eng/common/templates/steps/source-build.yml +++ b/eng/common/templates/steps/source-build.yml @@ -23,7 +23,7 @@ steps: # In addition, add an msbuild argument to copy the WIP from the repo to the target build location. # This is because SetupNuGetSources.sh will alter the current NuGet.config file, and we need to preserve those # changes. - $internalRestoreArgs= + internalRestoreArgs= if [ '$(dn-bot-dnceng-artifact-feeds-rw)' != '$''(dn-bot-dnceng-artifact-feeds-rw)' ]; then # Temporarily work around https://github.com/dotnet/arcade/issues/7709 chmod +x $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh diff --git a/eng/config/BannedSymbols.txt b/eng/config/BannedSymbols.txt index 371e0152dc035..90dc1530bd4d1 100644 --- a/eng/config/BannedSymbols.txt +++ b/eng/config/BannedSymbols.txt @@ -2,6 +2,7 @@ T:Microsoft.VisualStudio.Shell.Interop.IComWrapper; Use Microsoft.VisualStudio.L P:Microsoft.CodeAnalysis.Completion.CompletionContext.Options; Use CompletionOptions instead. M:Microsoft.CodeAnalysis.Completion.CompletionProvider.ShouldTriggerCompletion(Microsoft.CodeAnalysis.Text.SourceText,System.Int32,Microsoft.CodeAnalysis.Completion.CompletionTrigger,Microsoft.CodeAnalysis.Options.OptionSet); Use internal overload instead M:Microsoft.CodeAnalysis.Completion.CompletionProvider.GetDescriptionAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.Completion.CompletionItem,System.Threading.CancellationToken); Use internal overload instead -M:Microsoft.CodeAnalysis.Completion.CompletionService.GetCompletionsAsync(Microsoft.CodeAnalysis.Document,System.Int32,Microsoft.CodeAnalysis.Completion.CompletionTrigger,System.Collections.Immutable.ImmutableHashSet{System.String},Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use GetCompletionsInternalAsync instead +M:Microsoft.CodeAnalysis.Completion.CompletionService.GetCompletionsAsync(Microsoft.CodeAnalysis.Document,System.Int32,Microsoft.CodeAnalysis.Completion.CompletionTrigger,System.Collections.Immutable.ImmutableHashSet{System.String},Microsoft.CodeAnalysis.Options.OptionSet,System.Threading.CancellationToken); Use internal overload instead M:Microsoft.CodeAnalysis.Completion.CompletionService.GetDescriptionAsync(Microsoft.CodeAnalysis.Document,Microsoft.CodeAnalysis.Completion.CompletionItem,System.Threading.CancellationToken); Use internal overload instead M:Microsoft.CodeAnalysis.Completion.CompletionService.GetRules; Use internal overload instead +M:Microsoft.CodeAnalysis.QuickInfo.QuickInfoService.GetQuickInfoAsync(Microsoft.CodeAnalysis.Document,System.Int32,System.Threading.CancellationToken); Use internal overload instead \ No newline at end of file diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index ebf02b67bf5e5..6b0c9d7b2167e 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -210,20 +210,18 @@ "channels": [], "vsBranch": "rel/d17.1", "vsMajorVersion": 17, - "insertionCreateDraftPR": true, - "insertionTitlePrefix": "[d17.1p3]" + "insertionTitlePrefix": "[d17.1]" }, - "main-vs-deps": { + "release/dev17.2": { "nugetKind": [ "Shipping", "NonShipping" ], - "version": "4.1.*", + "version": "4.2.*", "packageFeeds": "default", "channels": [], - "vsBranch": "main", + "vsBranch": "rel/d17.2", "vsMajorVersion": 17, - "insertionCreateDraftPR": true, "insertionTitlePrefix": "[d17.2p1]" }, "main": { @@ -231,12 +229,13 @@ "Shipping", "NonShipping" ], - "version": "4.1.*", - "packageFeeds": "arcade", + "version": "4.2.*", + "packageFeeds": "default", "channels": [], "vsBranch": "main", "vsMajorVersion": 17, - "insertionTitlePrefix": "[Validation]" + "insertionCreateDraftPR": false, + "insertionTitlePrefix": "[d17.2p2]" }, "features/NullableReferenceTypes": { "nugetKind": "PerBuildPreRelease", diff --git a/eng/targets/Services.props b/eng/targets/Services.props index c4421f0d7a042..316192a92ea15 100644 --- a/eng/targets/Services.props +++ b/eng/targets/Services.props @@ -38,7 +38,7 @@ - + - - - - - \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs index 0fb4d250fc176..232eaa7b8118a 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs @@ -257,8 +257,9 @@ internal bool AreNullableAnnotationsEnabled(SyntaxTree syntaxTree, int position) Syntax.NullableContextState.State.Disabled => false, Syntax.NullableContextState.State.ExplicitlyRestored => GetGlobalAnnotationState(), Syntax.NullableContextState.State.Unknown => - !csTree.IsGeneratedCode(this.Compilation.Options.SyntaxTreeOptionsProvider, CancellationToken.None) - && AreNullableAnnotationsGloballyEnabled(), + // IsGeneratedCode may be slow, check global state first: + AreNullableAnnotationsGloballyEnabled() && + !csTree.IsGeneratedCode(this.Compilation.Options.SyntaxTreeOptionsProvider, CancellationToken.None), _ => throw ExceptionUtilities.UnexpectedValue(context.AnnotationsState) }; } @@ -269,12 +270,6 @@ internal bool AreNullableAnnotationsEnabled(SyntaxToken token) return AreNullableAnnotationsEnabled(token.SyntaxTree, token.SpanStart); } - internal bool IsGeneratedCode(SyntaxToken token) - { - var tree = (CSharpSyntaxTree)token.SyntaxTree!; - return tree.IsGeneratedCode(Compilation.Options.SyntaxTreeOptionsProvider, CancellationToken.None); - } - internal virtual bool AreNullableAnnotationsGloballyEnabled() { RoslynDebug.Assert(Next is object); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs index a81c1a8bb9a9b..7f81b7826e5bb 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs @@ -157,11 +157,7 @@ internal ImmutableArray BindTypeParameterConstrai } else if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag) { - LazyMissingNonNullTypesContextDiagnosticInfo.ReportNullableReferenceTypesIfNeeded( - AreNullableAnnotationsEnabled(questionToken), - IsGeneratedCode(questionToken), - questionToken.GetLocation(), - diagnosticBag); + LazyMissingNonNullTypesContextDiagnosticInfo.AddAll(this, questionToken, type: null, diagnosticBag); } } else if (isForOverride || AreNullableAnnotationsEnabled(constraintSyntax.ClassOrStructKeyword)) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 7afffae813852..b26433641f55b 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -461,7 +461,7 @@ private BoundExpression ConvertSwitchExpression(BoundUnconvertedSwitchExpression var newSwitchArms = builder.ToImmutableAndFree(); return new BoundConvertedSwitchExpression( - source.Syntax, source.Type, targetTyped, source.Expression, newSwitchArms, source.DecisionDag, + source.Syntax, source.Type, targetTyped, source.Expression, newSwitchArms, source.ReachabilityDecisionDag, source.DefaultLabel, source.ReportedNotExhaustive, destination, hasErrors || source.HasErrors).WithSuppression(source.IsSuppressed); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 61be80e94b9b3..81feaabf66212 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -5894,6 +5894,9 @@ private BoundLiteral BindLiteralConstant(LiteralExpressionSyntax node, BindingDi type = GetSpecialType(specialType, diagnostics, node); } + if (node.Token.Kind() is SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken) + MessageID.IDS_FeatureRawStringLiterals.CheckFeatureAvailability(diagnostics, node, node.Location); + return new BoundLiteral(node, cv, type); } @@ -8753,10 +8756,9 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) return null; } - if (!typeArguments.All(t => isValidTypeArgument(t.Type))) + if (!typeArguments.All(t => t.HasType)) { - // https://github.com/dotnet/roslyn/issues/55217: Support parameter - // and return types that are not valid generic type arguments. + // Invalid parameter or return type. return null; } @@ -8797,13 +8799,6 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) var typeDescr = new AnonymousTypeDescriptor(fieldsBuilder.ToImmutableAndFree(), location); return Compilation.AnonymousTypeManager.ConstructAnonymousDelegateSymbol(typeDescr); - static bool isValidTypeArgument(TypeSymbol? type) - { - return type is { } && - !type.IsPointerOrFunctionPointer() && - !type.IsRestrictedType(); - } - static bool checkConstraints(CSharpCompilation compilation, ConversionsBase conversions, NamedTypeSymbol delegateType, ImmutableArray typeArguments) { var diagnosticsBuilder = ArrayBuilder.GetInstance(); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs b/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs index a3ed2d0e89e43..b279cb12e7dc6 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs @@ -18,7 +18,15 @@ internal partial class Binder { private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSyntax node, BindingDiagnosticBag diagnostics) { - CheckFeatureAvailability(node, MessageID.IDS_FeatureInterpolatedStrings, diagnostics); + if (CheckFeatureAvailability(node, MessageID.IDS_FeatureInterpolatedStrings, diagnostics)) + { + // Only bother reporting an issue for raw string literals if we didn't already report above that + // interpolated strings are not allowed. + if (node.StringStartToken.Kind() is SyntaxKind.InterpolatedSingleLineRawStringStartToken or SyntaxKind.InterpolatedMultiLineRawStringStartToken) + { + CheckFeatureAvailability(node, MessageID.IDS_FeatureRawStringLiterals, diagnostics); + } + } var startText = node.StringStartToken.Text; if (startText.StartsWith("@$\"") && !Compilation.IsFeatureEnabled(MessageID.IDS_FeatureAltInterpolatedVerbatimStrings)) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs index bbc6eeabe3f64..4075977e98ce0 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs @@ -71,13 +71,13 @@ private BoundExpression MakeIsPatternExpression( { case BoundConstantPattern _: case BoundITuplePattern _: - case BoundListPattern: // these patterns can fail in practice throw ExceptionUtilities.Unreachable; case BoundRelationalPattern _: case BoundTypePattern _: case BoundNegatedPattern _: case BoundBinaryPattern _: + case BoundListPattern: Debug.Assert(expression.Type is object); diagnostics.Add(ErrorCode.WRN_IsPatternAlways, node.Location, expression.Type); break; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index 8bfa775b936f4..6eaa2f6ef23b5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -490,30 +490,16 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasS void reportNullableReferenceTypesIfNeeded(SyntaxToken questionToken, TypeWithAnnotations typeArgument = default) { - bool isNullableEnabled = AreNullableAnnotationsEnabled(questionToken); - bool isGeneratedCode = IsGeneratedCode(questionToken); - var location = questionToken.GetLocation(); - if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag) { // Inside a method body or other executable code, we can question IsValueType without causing cycles. if (typeArgument.HasType && !ShouldCheckConstraints) { - LazyMissingNonNullTypesContextDiagnosticInfo.AddAll( - isNullableEnabled, - isGeneratedCode, - typeArgument, - location, - diagnosticBag); + LazyMissingNonNullTypesContextDiagnosticInfo.AddAll(this, questionToken, typeArgument, diagnosticBag); } - else + else if (LazyMissingNonNullTypesContextDiagnosticInfo.IsNullableReference(typeArgument.Type)) { - LazyMissingNonNullTypesContextDiagnosticInfo.ReportNullableReferenceTypesIfNeeded( - isNullableEnabled, - isGeneratedCode, - typeArgument, - location, - diagnosticBag); + LazyMissingNonNullTypesContextDiagnosticInfo.AddAll(this, questionToken, type: null, diagnosticBag); } } } diff --git a/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs b/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs index 1e60285339857..b0de138eae619 100644 --- a/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs +++ b/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs @@ -60,13 +60,20 @@ internal sealed partial class DecisionDagBuilder private readonly Conversions _conversions; private readonly BindingDiagnosticBag _diagnostics; private readonly LabelSymbol _defaultLabel; + /// + /// We might need to build a dedicated dag for lowering during which we + /// avoid synthesizing tests to relate alternative indexers. This won't + /// affect code semantics but it results in a better code generation. + /// + private readonly bool _forLowering; - private DecisionDagBuilder(CSharpCompilation compilation, LabelSymbol defaultLabel, BindingDiagnosticBag diagnostics) + private DecisionDagBuilder(CSharpCompilation compilation, LabelSymbol defaultLabel, bool forLowering, BindingDiagnosticBag diagnostics) { this._compilation = compilation; this._conversions = compilation.Conversions; _diagnostics = diagnostics; _defaultLabel = defaultLabel; + _forLowering = forLowering; } /// @@ -78,9 +85,10 @@ public static BoundDecisionDag CreateDecisionDagForSwitchStatement( BoundExpression switchGoverningExpression, ImmutableArray switchSections, LabelSymbol defaultLabel, - BindingDiagnosticBag diagnostics) + BindingDiagnosticBag diagnostics, + bool forLowering = false) { - var builder = new DecisionDagBuilder(compilation, defaultLabel, diagnostics); + var builder = new DecisionDagBuilder(compilation, defaultLabel, forLowering, diagnostics); return builder.CreateDecisionDagForSwitchStatement(syntax, switchGoverningExpression, switchSections); } @@ -93,9 +101,10 @@ public static BoundDecisionDag CreateDecisionDagForSwitchExpression( BoundExpression switchExpressionInput, ImmutableArray switchArms, LabelSymbol defaultLabel, - BindingDiagnosticBag diagnostics) + BindingDiagnosticBag diagnostics, + bool forLowering = false) { - var builder = new DecisionDagBuilder(compilation, defaultLabel, diagnostics); + var builder = new DecisionDagBuilder(compilation, defaultLabel, forLowering, diagnostics); return builder.CreateDecisionDagForSwitchExpression(syntax, switchExpressionInput, switchArms); } @@ -109,9 +118,10 @@ public static BoundDecisionDag CreateDecisionDagForIsPattern( BoundPattern pattern, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, - BindingDiagnosticBag diagnostics) + BindingDiagnosticBag diagnostics, + bool forLowering = false) { - var builder = new DecisionDagBuilder(compilation, defaultLabel: whenFalseLabel, diagnostics); + var builder = new DecisionDagBuilder(compilation, defaultLabel: whenFalseLabel, forLowering, diagnostics); return builder.CreateDecisionDagForIsPattern(syntax, inputExpression, pattern, whenTrueLabel); } @@ -421,8 +431,12 @@ private static void MakeCheckNotNull( ArrayBuilder tests) { // Add a null test if needed - if (input.Type.CanContainNull()) + if (input.Type.CanContainNull() && + // The slice value is assumed to be never null + input.Source is not BoundDagSliceEvaluation) + { tests.Add(new Tests.One(new BoundDagNonNullTest(syntax, isExplicitTest, input))); + } } /// @@ -1336,7 +1350,7 @@ void handleRelationWithValue( /// Returns true if the tests are related i.e. they have the same input, otherwise false. /// The pre-condition under which these tests are related. /// A possible assignment node which will correspond two non-identical but related test inputs. - private static bool CheckInputRelation( + private bool CheckInputRelation( SyntaxNode syntax, DagState state, BoundDagTest test, @@ -1426,7 +1440,7 @@ other is not (BoundDagNonNullTest or BoundDagExplicitNullTest) && continue; } - if (lengthValues.Any(BinaryOperatorKind.Equal, lengthValue)) + if (!_forLowering && lengthValues.Any(BinaryOperatorKind.Equal, lengthValue)) { // Otherwise, we add a test to make the result conditional on the length value. (conditions ??= ArrayBuilder.GetInstance()).Add(new Tests.One(new BoundDagValueTest(syntax, ConstantValue.Create(lengthValue), s1LengthTemp))); @@ -1971,7 +1985,7 @@ public override void Filter( SyntaxNode syntax = test.Syntax; BoundDagTest other = this.Test; if (other is BoundDagEvaluation || - !CheckInputRelation(syntax, state, test, other, + !builder.CheckInputRelation(syntax, state, test, other, relationCondition: out Tests relationCondition, relationEffect: out Tests relationEffect)) { diff --git a/src/Compilers/CSharp/Portable/Binder/EarlyWellKnownAttributeBinder.cs b/src/Compilers/CSharp/Portable/Binder/EarlyWellKnownAttributeBinder.cs index 149a790972594..5a2040024594f 100644 --- a/src/Compilers/CSharp/Portable/Binder/EarlyWellKnownAttributeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/EarlyWellKnownAttributeBinder.cs @@ -39,13 +39,11 @@ internal EarlyWellKnownAttributeBinder(Binder enclosing) // Hide the GetAttribute overload which takes a diagnostic bag. // This ensures that diagnostics from the early bound attributes are never preserved. [Obsolete("EarlyWellKnownAttributeBinder has a better overload - GetAttribute(AttributeSyntax, NamedTypeSymbol, out bool)", true)] -#pragma warning disable format // https://github.com/dotnet/roslyn/issues/56498 internal new (CSharpAttributeData, BoundAttribute) GetAttribute( AttributeSyntax node, NamedTypeSymbol boundAttributeType, Action beforeAttributePartBound, Action afterAttributePartBound, BindingDiagnosticBag diagnostics) -#pragma warning restore format { Debug.Assert(false, "Don't call this overload."); diagnostics.Add(ErrorCode.ERR_InternalError, node.Location); diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index c5c81078d7683..6d74eb782fa80 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -628,10 +628,11 @@ private Conversion ClassifyStandardImplicitConversion(BoundExpression sourceExpr // // We extend the definition of standard implicit conversions to include // all of the implicit conversions that are allowed based on an expression, - // with the exception of the switch expression conversion. + // with the exception of the switch expression conversion and the interpolated + // string builder conversion. Conversion conversion = ClassifyImplicitBuiltInConversionFromExpression(sourceExpression, source, destination, ref useSiteInfo); - if (conversion.Exists) + if (conversion.Exists && !conversion.IsInterpolatedStringHandler) { Debug.Assert(IsStandardImplicitConversionFromExpression(conversion.Kind)); return conversion; diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/UserDefinedImplicitConversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/UserDefinedImplicitConversions.cs index a1e447450d3af..f9e5b4c41103e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/UserDefinedImplicitConversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/UserDefinedImplicitConversions.cs @@ -605,6 +605,7 @@ private static bool IsEncompassingImplicitConversionKind(ConversionKind kind) case ConversionKind.ImplicitEnumeration: case ConversionKind.StackAllocToPointerType: case ConversionKind.StackAllocToSpanType: + case ConversionKind.InterpolatedStringHandler: // Not "standard". case ConversionKind.ImplicitUserDefined: @@ -646,6 +647,9 @@ private static bool IsEncompassingImplicitConversionKind(ConversionKind kind) // Added for C# 7.1 case ConversionKind.DefaultLiteral: + + // Added for C# 9 + case ConversionKind.ImplicitPointer: return true; default: diff --git a/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs index 663cf587745b9..056c43b0a76b0 100644 --- a/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs @@ -66,7 +66,7 @@ internal override BoundStatement BindSwitchStatementCore(SwitchStatementSyntax n switchSections: switchSections, defaultLabel: defaultLabel, breakLabel: this.BreakLabel, - decisionDag: decisionDag); + reachabilityDecisionDag: decisionDag); } private void CheckSwitchErrors( diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs index 86b8f600227cd..225e669051bcb 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs @@ -194,6 +194,11 @@ BoundDecisionDagNode makeReplacement(BoundDecisionDagNode dag, IReadOnlyDictiona } } + public bool ContainsAnySynthesizedNodes() + { + return this.TopologicallySortedNodes.Any(node => node is BoundEvaluationDecisionDagNode e && e.Evaluation.Kind == BoundKind.DagAssignmentEvaluation); + } + #if DEBUG /// /// Starting with `this` state, produce a human-readable description of the state tables. diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundIsPatternExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundIsPatternExpression.cs new file mode 100644 index 0000000000000..a5500883aa3c0 --- /dev/null +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundIsPatternExpression.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace Microsoft.CodeAnalysis.CSharp +{ + internal partial class BoundIsPatternExpression + { + public BoundDecisionDag GetDecisionDagForLowering(CSharpCompilation compilation) + { + BoundDecisionDag decisionDag = this.ReachabilityDecisionDag; + if (decisionDag.ContainsAnySynthesizedNodes()) + { + decisionDag = DecisionDagBuilder.CreateDecisionDagForIsPattern( + compilation, + this.Syntax, + this.Expression, + this.Pattern, + this.WhenTrueLabel, + this.WhenFalseLabel, + BindingDiagnosticBag.Discarded, + forLowering: true); + Debug.Assert(!decisionDag.ContainsAnySynthesizedNodes()); + } + + return decisionDag; + } + } +} diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index 819613f95226e..1994cdcd5f617 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -1088,7 +1088,7 @@ - + @@ -1411,7 +1411,7 @@ - + @@ -2200,7 +2200,7 @@ - + diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundSwitchExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundSwitchExpression.cs new file mode 100644 index 0000000000000..d86b6cddf4900 --- /dev/null +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundSwitchExpression.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Symbols; + +namespace Microsoft.CodeAnalysis.CSharp +{ + internal partial class BoundSwitchExpression + { + public BoundDecisionDag GetDecisionDagForLowering(CSharpCompilation compilation, out LabelSymbol? defaultLabel) + { + defaultLabel = this.DefaultLabel; + + BoundDecisionDag decisionDag = this.ReachabilityDecisionDag; + if (decisionDag.ContainsAnySynthesizedNodes()) + { + decisionDag = DecisionDagBuilder.CreateDecisionDagForSwitchExpression( + compilation, + this.Syntax, + this.Expression, + this.SwitchArms, + // there's no default label if the original switch is exhaustive. + // we generate a new label here because the new dag might not be. + defaultLabel ??= new GeneratedLabelSymbol("default"), + BindingDiagnosticBag.Discarded, + forLowering: true); + Debug.Assert(!decisionDag.ContainsAnySynthesizedNodes()); + } + + return decisionDag; + } + } +} diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundSwitchStatement.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundSwitchStatement.cs index 5081c02cb8e23..5f009c96a3dbe 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundSwitchStatement.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundSwitchStatement.cs @@ -3,12 +3,29 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Diagnostics; namespace Microsoft.CodeAnalysis.CSharp { - internal partial class BoundSwitchStatement : IBoundSwitchStatement + internal partial class BoundSwitchStatement { - BoundNode IBoundSwitchStatement.Value => this.Expression; - ImmutableArray IBoundSwitchStatement.Cases => StaticCast.From(this.SwitchSections); + public BoundDecisionDag GetDecisionDagForLowering(CSharpCompilation compilation) + { + BoundDecisionDag decisionDag = this.ReachabilityDecisionDag; + if (decisionDag.ContainsAnySynthesizedNodes()) + { + decisionDag = DecisionDagBuilder.CreateDecisionDagForSwitchStatement( + compilation, + this.Syntax, + this.Expression, + this.SwitchSections, + this.DefaultLabel?.Label ?? this.BreakLabel, + BindingDiagnosticBag.Discarded, + forLowering: true); + Debug.Assert(!decisionDag.ContainsAnySynthesizedNodes()); + } + + return decisionDag; + } } } diff --git a/src/Compilers/CSharp/Portable/CSharpCompilationOptions.cs b/src/Compilers/CSharp/Portable/CSharpCompilationOptions.cs index 9036a9782fe9a..93aa69cd6a7db 100644 --- a/src/Compilers/CSharp/Portable/CSharpCompilationOptions.cs +++ b/src/Compilers/CSharp/Portable/CSharpCompilationOptions.cs @@ -271,6 +271,8 @@ internal CSharpCompilationOptions WithTopLevelBinderFlags(BinderFlags flags) internal override ImmutableArray GetImports() => Usings; + internal override DeterministicKeyBuilder CreateDeterministicKeyBuilder() => CSharpDeterministicKeyBuilder.Instance; + public new CSharpCompilationOptions WithOutputKind(OutputKind kind) { if (kind == this.OutputKind) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 9e8f50c20a240..995bd5bbdd7ea 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6169,8 +6169,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Duplicate null suppression operator ('!') - - Incorrect parameter null checking syntax. Should be '!!'. + + Discard parameter cannot be null-checked. Parameter '{0}' can only have exclamation-point null checking in implementation methods. @@ -6184,8 +6184,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Parameter is null-checked but is null by default. - - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. Nullable type '{0}' is null-checked and will throw if null. @@ -6757,9 +6757,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ list pattern - - length pattern - List patterns may not be used for a value of type '{0}'. @@ -6896,6 +6893,48 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ At least one top-level statement must be non-empty. + + Line does not start with the same whitespace as the closing line of the raw string literal. + + + Raw string literals are not allowed in preprocessor directives. + + + Raw string literal delimiter must be on its own line. + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + Not enough quotes for raw string literal. + + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + + String must start with quote character: " + + + Unterminated raw string literal. + + + raw string literals + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + Multi-line raw string literals must contain at least one line of content. + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. @@ -6917,6 +6956,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ A 'struct' with field initializers must include an explicitly declared constructor. + + Cannot update because an inferred delegate type has changed. + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) @@ -6962,4 +7004,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Required member '{0}' must be settable. + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs index 64777db3b8094..87493b630f76b 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs @@ -25,8 +25,8 @@ internal abstract class CSharpCompiler : CommonCompiler private readonly CommandLineDiagnosticFormatter _diagnosticFormatter; private readonly string? _tempDirectory; - protected CSharpCompiler(CSharpCommandLineParser parser, string? responseFile, string[] args, BuildPaths buildPaths, string? additionalReferenceDirectories, IAnalyzerAssemblyLoader assemblyLoader, GeneratorDriverCache? driverCache = null) - : base(parser, responseFile, args, buildPaths, additionalReferenceDirectories, assemblyLoader, driverCache) + protected CSharpCompiler(CSharpCommandLineParser parser, string? responseFile, string[] args, BuildPaths buildPaths, string? additionalReferenceDirectories, IAnalyzerAssemblyLoader assemblyLoader, GeneratorDriverCache? driverCache = null, ICommonCompilerFileSystem? fileSystem = null) + : base(parser, responseFile, args, buildPaths, additionalReferenceDirectories, assemblyLoader, driverCache, fileSystem) { _diagnosticFormatter = new CommandLineDiagnosticFormatter(buildPaths.WorkingDirectory, Arguments.PrintFullPaths, Arguments.ShouldIncludeErrorEndLocation); _tempDirectory = buildPaths.TempDirectory; diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 875093a533ff0..e7fbc39ea4d49 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Reflection; using System.Reflection.Metadata; +using System.Text; using System.Threading; using Microsoft.Cci; using Microsoft.CodeAnalysis; @@ -3274,15 +3275,15 @@ private void GenerateModuleInitializer(PEModuleBuilder moduleBeingBuilt, Diagnos } } - internal override bool GenerateResourcesAndDocumentationComments( + internal override bool GenerateResources( CommonPEModuleBuilder moduleBuilder, - Stream? xmlDocStream, Stream? win32Resources, bool useRawWin32Resources, - string? outputNameOverride, DiagnosticBag diagnostics, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + // Use a temporary bag so we don't have to refilter pre-existing diagnostics. DiagnosticBag? resourceDiagnostics = DiagnosticBag.GetInstance(); @@ -3294,11 +3295,15 @@ internal override bool GenerateResourcesAndDocumentationComments( AddedModulesResourceNames(resourceDiagnostics), resourceDiagnostics); - if (!FilterAndAppendAndFreeDiagnostics(diagnostics, ref resourceDiagnostics, cancellationToken)) - { - return false; - } + return FilterAndAppendAndFreeDiagnostics(diagnostics, ref resourceDiagnostics, cancellationToken); + } + internal override bool GenerateDocumentationComments( + Stream? xmlDocStream, + string? outputNameOverride, + DiagnosticBag diagnostics, + CancellationToken cancellationToken) + { cancellationToken.ThrowIfCancellationRequested(); // Use a temporary bag so we don't have to refilter pre-existing diagnostics. diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpDeterministicKeyBuilder.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpDeterministicKeyBuilder.cs new file mode 100644 index 0000000000000..29e2bee7f183b --- /dev/null +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpDeterministicKeyBuilder.cs @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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 Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp +{ + internal sealed class CSharpDeterministicKeyBuilder : DeterministicKeyBuilder + { + internal static readonly CSharpDeterministicKeyBuilder Instance = new(); + + private CSharpDeterministicKeyBuilder() + { + } + + protected override void WriteCompilationOptionsCore(JsonWriter writer, CompilationOptions options) + { + if (options is not CSharpCompilationOptions csharpOptions) + { + throw new ArgumentException(null, nameof(options)); + } + + base.WriteCompilationOptionsCore(writer, options); + + writer.Write("unsafe", csharpOptions.AllowUnsafe); + writer.Write("topLevelBinderFlags", csharpOptions.TopLevelBinderFlags); + writer.WriteKey("usings"); + writer.WriteArrayStart(); + foreach (var name in csharpOptions.Usings) + { + writer.Write(name); + } + writer.WriteArrayEnd(); + } + + protected override void WriteParseOptionsCore(JsonWriter writer, ParseOptions parseOptions) + { + if (parseOptions is not CSharpParseOptions csharpOptions) + { + throw new ArgumentException(null, nameof(parseOptions)); + } + + base.WriteParseOptionsCore(writer, parseOptions); + + writer.Write("languageVersion", csharpOptions.LanguageVersion); + writer.Write("specifiedLanguageVersion", csharpOptions.SpecifiedLanguageVersion); + + writer.WriteKey("preprocessorSymbols"); + writer.WriteArrayStart(); + + // Even though tools like the command line parser don't explicitly order the symbols + // here the order doesn't actually impact determinism. + foreach (var symbol in csharpOptions.PreprocessorSymbols.OrderBy(StringComparer.Ordinal)) + { + writer.Write(symbol); + } + + writer.WriteArrayEnd(); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpDiagnosticFilter.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpDiagnosticFilter.cs index 1303fc56c371d..56ea9ca949dfd 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpDiagnosticFilter.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpDiagnosticFilter.cs @@ -159,7 +159,8 @@ internal static ReportDiagnostic GetDiagnosticReport( Syntax.NullableContextState.State.Disabled => false, Syntax.NullableContextState.State.ExplicitlyRestored => nullableOption.WarningsEnabled(), Syntax.NullableContextState.State.Unknown => - tree?.IsGeneratedCode(syntaxTreeOptions, cancellationToken) != true && nullableOption.WarningsEnabled(), + // IsGeneratedCode may be slow, check the option first: + nullableOption.WarningsEnabled() && tree?.IsGeneratedCode(syntaxTreeOptions, cancellationToken) != true, null => nullableOption.WarningsEnabled(), _ => throw ExceptionUtilities.UnexpectedValue(warningsState) }; diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index 0b0bf6249fc41..3f6167f425685 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs @@ -5139,6 +5139,7 @@ internal override void ComputeDeclarationsInNode(SyntaxNode node, ISymbol associ } internal abstract override Func GetSyntaxNodesToAnalyzeFilter(SyntaxNode declaredNode, ISymbol declaredSymbol); + internal abstract override bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol); protected internal override SyntaxNode GetTopmostNodeForDiagnosticAnalysis(ISymbol symbol, SyntaxNode declaringSyntax) { @@ -5297,24 +5298,30 @@ protected sealed override bool IsEventUsableAsFieldCore(int position, IEventSymb public sealed override NullableContext GetNullableContext(int position) { var syntaxTree = (CSharpSyntaxTree)Root.SyntaxTree; - NullableContextState contextState = syntaxTree.GetNullableContextState(position); - var defaultState = syntaxTree.IsGeneratedCode(Compilation.Options.SyntaxTreeOptionsProvider, CancellationToken.None) - ? NullableContextOptions.Disable - : Compilation.Options.NullableContextOptions; - NullableContext context = getFlag(contextState.AnnotationsState, defaultState.AnnotationsEnabled(), NullableContext.AnnotationsContextInherited, NullableContext.AnnotationsEnabled); - context |= getFlag(contextState.WarningsState, defaultState.WarningsEnabled(), NullableContext.WarningsContextInherited, NullableContext.WarningsEnabled); + NullableContextOptions? lazyDefaultState = null; + NullableContextState contextState = syntaxTree.GetNullableContextState(position); - return context; + return contextState.AnnotationsState switch + { + NullableContextState.State.Enabled => NullableContext.AnnotationsEnabled, + NullableContextState.State.Disabled => NullableContext.Disabled, + _ when getDefaultState().AnnotationsEnabled() => NullableContext.AnnotationsContextInherited | NullableContext.AnnotationsEnabled, + _ => NullableContext.AnnotationsContextInherited, + } + | contextState.WarningsState switch + { + NullableContextState.State.Enabled => NullableContext.WarningsEnabled, + NullableContextState.State.Disabled => NullableContext.Disabled, + _ when getDefaultState().WarningsEnabled() => NullableContext.WarningsContextInherited | NullableContext.WarningsEnabled, + _ => NullableContext.WarningsContextInherited, + }; - static NullableContext getFlag(NullableContextState.State contextState, bool defaultEnableState, NullableContext inheritedFlag, NullableContext enableFlag) => - contextState switch - { - NullableContextState.State.Enabled => enableFlag, - NullableContextState.State.Disabled => NullableContext.Disabled, - _ when defaultEnableState => (inheritedFlag | enableFlag), - _ => inheritedFlag, - }; + // IsGeneratedCode might be slow, only call it when needed: + NullableContextOptions getDefaultState() + => lazyDefaultState ??= syntaxTree.IsGeneratedCode(Compilation.Options.SyntaxTreeOptionsProvider, CancellationToken.None) + ? NullableContextOptions.Disable + : Compilation.Options.NullableContextOptions; } #endregion diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index b2ec4487ff52c..8d106bcd64aa9 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -2360,6 +2360,11 @@ internal sealed override Func GetSyntaxNodesToAnalyzeFilter(Sy throw ExceptionUtilities.Unreachable; } + internal override bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol) + { + throw ExceptionUtilities.Unreachable; + } + /// /// The incremental binder is used when binding statements. Whenever a statement /// is bound, it checks the bound node cache to see if that statement was bound, diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs index c7ed1784361d5..de7e69c328793 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs @@ -2528,5 +2528,28 @@ internal override Func GetSyntaxNodesToAnalyzeFilter(SyntaxNod return null; } + + internal override bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol) + { + if (containingSymbol.Kind is SymbolKind.Method) + { + switch (node) + { + case RecordDeclarationSyntax: + // Skip the topmost record declaration syntax node when analyzing synthesized record declaration constructor + // to avoid duplicate syntax node callbacks. + // We will analyze this node when analyzing the record declaration type symbol. + return true; + + case CompilationUnitSyntax: + // Skip compilation unit syntax node when analyzing synthesized top level entry point method + // to avoid duplicate syntax node callbacks. + // We will analyze this node when analyzing the global namespace symbol. + return true; + } + } + + return false; + } } } diff --git a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.DocumentationCommentWalker.cs b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.DocumentationCommentWalker.cs index 43f803957ba9a..1337454450567 100644 --- a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.DocumentationCommentWalker.cs +++ b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.DocumentationCommentWalker.cs @@ -5,8 +5,10 @@ #nullable disable using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; +using System.Text; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -23,12 +25,13 @@ internal partial class DocumentationCommentCompiler : CSharpSymbolVisitor /// Walks a DocumentationCommentTriviaSyntax, binding the semantically meaningful parts /// to produce diagnostics and to replace source crefs with documentation comment IDs. /// + [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] private class DocumentationCommentWalker : CSharpSyntaxWalker { private readonly CSharpCompilation _compilation; private readonly BindingDiagnosticBag _diagnostics; private readonly Symbol _memberSymbol; - private readonly TextWriter _writer; + private readonly StringWriter _writer; private readonly ArrayBuilder _includeElementNodes; private HashSet _documentedParameters; @@ -38,7 +41,7 @@ private DocumentationCommentWalker( CSharpCompilation compilation, BindingDiagnosticBag diagnostics, Symbol memberSymbol, - TextWriter writer, + StringWriter writer, ArrayBuilder includeElementNodes, HashSet documentedParameters, HashSet documentedTypeParameters) @@ -54,6 +57,56 @@ private DocumentationCommentWalker( _documentedTypeParameters = documentedTypeParameters; } + /// + /// Writes the matching 'param' tags on a primary constructor as 'summary' tags for a synthesized record property. + /// + /// + /// Still has all of the comment punctuation (///, /**, etc). associated with the 'param' tag. + /// + public static void GetSubstitutedText( + CSharpCompilation compilation, + SynthesizedRecordPropertySymbol symbol, + ArrayBuilder paramElements, + ArrayBuilder includeElementNodes, + StringBuilder builder) + { + StringWriter writer = new StringWriter(builder, CultureInfo.InvariantCulture); + DocumentationCommentWalker walker = new DocumentationCommentWalker(compilation, BindingDiagnosticBag.Discarded, symbol, writer, includeElementNodes, documentedParameters: null, documentedTypeParameters: null); + + // Before: CONTENT + // After: CONTENT + foreach (var paramElement in paramElements) + { + // '///' token doesn't own the following new line. Instead, it is directly followed by an 'XmlTextLiteralNewLineToken'. + if (endGreaterThanToken.GetNextToken() is SyntaxToken newLineToken && newLineToken.IsKind(SyntaxKind.XmlTextLiteralNewLineToken)) + { + walker.VisitToken(newLineToken); + } + } + } + /// /// Given a DocumentationCommentTriviaSyntax, return the full text, but with /// documentation comment IDs substituted into crefs. @@ -166,6 +219,11 @@ public override void VisitToken(SyntaxToken token) base.VisitToken(token); } + + private string GetDebuggerDisplay() + { + return _writer.GetStringBuilder().ToString(); + } } } } diff --git a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs index a1cece89a6e0a..42708c767e759 100644 --- a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Reflection; @@ -235,6 +236,8 @@ public override void VisitNamedType(NamedTypeSymbol symbol) } } +#nullable enable + /// /// Compile documentation comments on the symbol and write them to the stream if one is provided. /// @@ -279,9 +282,9 @@ public override void DefaultVisit(Symbol symbol) } } - DocumentationMode maxDocumentationMode; - ImmutableArray docCommentNodes; - if (!TryGetDocumentationCommentNodes(symbol, out maxDocumentationMode, out docCommentNodes)) + // synthesized record property: emit the matching param doc on containing type as the summary doc of the property. + var symbolForDocComments = symbol is SynthesizedRecordPropertySymbol ? symbol.ContainingType : symbol; + if (!TryGetDocumentationCommentNodes(symbolForDocComments, out var maxDocumentationMode, out var docCommentNodes)) { // If the XML in any of the doc comments is invalid, skip all further processing (for this symbol) and // just write a comment saying that info was lost for this symbol. @@ -351,7 +354,7 @@ public override void DefaultVisit(Symbol symbol) // NOTE: we are expanding include elements AFTER formatting the comment, since the included text is pure // XML, not XML mixed with documentation comment trivia (e.g. ///). If we expanded them before formatting, // the formatting engine would have trouble determining what prefix to remove from each line. - TextWriter expanderWriter = shouldSkipPartialDefinitionComments ? null : _writer; // Don't actually write partial method definition parts. + TextWriter? expanderWriter = shouldSkipPartialDefinitionComments ? null : _writer; // Don't actually write partial method definition parts. IncludeElementExpander.ProcessIncludes(withUnprocessedIncludes, symbol, includeElementNodes, _compilation, ref documentedParameters, ref documentedTypeParameters, ref _includedFileCache, expanderWriter, _diagnostics, _cancellationToken); } @@ -375,7 +378,7 @@ public override void DefaultVisit(Symbol symbol) if (!documentedParameters.Contains(parameter)) { Location location = parameter.Locations[0]; - Debug.Assert(location.SourceTree.ReportDocumentationCommentDiagnostics()); //Should be the same tree as for the symbol. + Debug.Assert(location.SourceTree!.ReportDocumentationCommentDiagnostics()); //Should be the same tree as for the symbol. // NOTE: parameter name, since the parameter would be displayed as just its type. _diagnostics.Add(ErrorCode.WRN_MissingParamTag, location, parameter.Name, symbol); @@ -390,7 +393,7 @@ public override void DefaultVisit(Symbol symbol) if (!documentedTypeParameters.Contains(typeParameter)) { Location location = typeParameter.Locations[0]; - Debug.Assert(location.SourceTree.ReportDocumentationCommentDiagnostics()); //Should be the same tree as for the symbol. + Debug.Assert(location.SourceTree!.ReportDocumentationCommentDiagnostics()); //Should be the same tree as for the symbol. _diagnostics.Add(ErrorCode.WRN_MissingTypeParamTag, location, typeParameter, symbol); } @@ -403,10 +406,73 @@ private static bool ShouldSkip(Symbol symbol) { return symbol.IsImplicitlyDeclared || symbol.IsAccessor() || - symbol is SynthesizedSimpleProgramEntryPointSymbol || - symbol is SynthesizedRecordPropertySymbol; + symbol is SynthesizedSimpleProgramEntryPointSymbol; + } + + private bool TryProcessRecordPropertyDocumentation( + SynthesizedRecordPropertySymbol recordPropertySymbol, + ImmutableArray docCommentNodes, + [NotNullWhen(true)] out string? withUnprocessedIncludes, + out ImmutableArray includeElementNodes) + { + _cancellationToken.ThrowIfCancellationRequested(); + + if (getMatchingParamTags(recordPropertySymbol.Name, docCommentNodes) is not { } paramTags) + { + withUnprocessedIncludes = null; + includeElementNodes = default; + return false; + } + + Debug.Assert(paramTags.Count > 0); + + BeginTemporaryString(); + WriteLine("", recordPropertySymbol.GetDocumentationCommentId()); + Indent(); + var substitutedTextBuilder = PooledStringBuilder.GetInstance(); + var includeElementNodesBuilder = _processIncludes ? ArrayBuilder.GetInstance() : null; + DocumentationCommentWalker.GetSubstitutedText(_compilation, recordPropertySymbol, paramTags, includeElementNodesBuilder, substitutedTextBuilder.Builder); + string substitutedText = substitutedTextBuilder.ToStringAndFree(); + string formattedXml = FormatComment(substitutedText); + Write(formattedXml); + Unindent(); + WriteLine(""); + + withUnprocessedIncludes = GetAndEndTemporaryString(); + includeElementNodes = includeElementNodesBuilder?.ToImmutableAndFree() ?? default; + + paramTags.Free(); + return true; + + static ArrayBuilder? getMatchingParamTags(string propertyName, ImmutableArray docCommentNodes) + { + ArrayBuilder? result = null; + foreach (var trivia in docCommentNodes) + { + foreach (var contentItem in trivia.Content) + { + if (contentItem is XmlElementSyntax elementSyntax) + { + foreach (var attribute in elementSyntax.StartTag.Attributes) + { + if (attribute is XmlNameAttributeSyntax nameAttribute + && nameAttribute.GetElementKind() == XmlNameAttributeElementKind.Parameter + && string.Equals(nameAttribute.Identifier.Identifier.ValueText, propertyName, StringComparison.Ordinal)) + { + result ??= ArrayBuilder.GetInstance(); + result.Add(elementSyntax); + break; + } + } + } + } + } + return result; + } } +#nullable disable + /// /// Loop over the DocumentationCommentTriviaSyntaxes. Gather /// 1) concatenated XML, as a string; @@ -440,6 +506,11 @@ private bool TryProcessDocumentationCommentTriviaNodes( // Saw an XmlException while parsing one of the DocumentationCommentTriviaSyntax nodes. haveParseError = false; + if (symbol is SynthesizedRecordPropertySymbol recordProperty) + { + return TryProcessRecordPropertyDocumentation(recordProperty, docCommentNodes, out withUnprocessedIncludes, out includeElementNodes); + } + // We're doing substitution and formatting per-trivia, rather than per-symbol, // because a single symbol can have both single-line and multi-line style // doc comments. @@ -706,7 +777,12 @@ private string FormatComment(string substitutedText) Debug.Assert(numLines > 0); } - Debug.Assert(TrimmedStringStartsWith(lines[0], "/**")); + // We may use multi-line formatting in a "fragment" scenario. + // /** The record + // The parameter + // */ + // record Rec(int P); + // When formatting docs for property 'Rec.P' we may have just the line with '' as input to this method. WriteFormattedMultiLineComment(lines, numLines); } @@ -897,7 +973,12 @@ private void WriteFormattedMultiLineComment(string[] lines, int numLines) { trimmed = TrimEndOfMultiLineComment(trimmed); } - WriteLine(trimmed.Substring(SyntaxFacts.IsWhitespace(trimmed[3]) ? 4 : 3)); + WriteLine(trimmed.Substring( + trimmed.StartsWith("/** ") ? 4 : + trimmed.StartsWith("/**") ? 3 : + trimmed.StartsWith("* ") ? 2 : + trimmed.StartsWith("*") ? 1 : + 0)); } for (int i = 1; i < numLines; i++) diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index b2a274c519301..29ed8c74a05ca 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -470,10 +470,6 @@ private void CompileNamedType(NamedTypeSymbol containingType) } } - // Indicates if a static constructor is in the member, - // so we can decide to synthesize a static constructor. - bool hasStaticConstructor = false; - var members = containingType.GetMembers(); for (int memberOrdinal = 0; memberOrdinal < members.Length; memberOrdinal++) { @@ -527,12 +523,6 @@ private void CompileNamedType(NamedTypeSymbol containingType) default(Binder.ProcessedFieldInitializers); CompileMethod(method, memberOrdinal, ref processedInitializers, synthesizedSubmissionFields, compilationState); - - // Set a flag to indicate that a static constructor is created. - if (method.MethodKind == MethodKind.StaticConstructor) - { - hasStaticConstructor = true; - } break; } @@ -596,45 +586,47 @@ private void CompileNamedType(NamedTypeSymbol containingType) } } - // In the case there are field initializers but we haven't created an implicit static constructor (.cctor) for it, - // (since we may not add .cctor implicitly created for decimals into the symbol table) - // it is necessary for the compiler to generate the static constructor here if we are emitting. - if (_moduleBeingBuiltOpt != null && !hasStaticConstructor && !processedStaticInitializers.BoundInitializers.IsDefaultOrEmpty) + if (containingType.StaticConstructors.IsEmpty) { - Debug.Assert(processedStaticInitializers.BoundInitializers.All((init) => - (init.Kind == BoundKind.FieldEqualsValue) && !((BoundFieldEqualsValue)init).Field.IsMetadataConstant)); - - MethodSymbol method = new SynthesizedStaticConstructor(sourceTypeSymbol); - if (PassesFilter(_filterOpt, method)) + // In the case there are field initializers but we haven't created an implicit static constructor (.cctor) for it, + // (since we may not add .cctor implicitly created for decimals into the symbol table) + // it is necessary for the compiler to generate the static constructor here if we are emitting. + if (_moduleBeingBuiltOpt != null && !processedStaticInitializers.BoundInitializers.IsDefaultOrEmpty) { - CompileMethod(method, -1, ref processedStaticInitializers, synthesizedSubmissionFields, compilationState); + Debug.Assert(processedStaticInitializers.BoundInitializers.All((init) => + (init.Kind == BoundKind.FieldEqualsValue) && !((BoundFieldEqualsValue)init).Field.IsMetadataConstant)); - // If this method has been successfully built, we emit it. - if (_moduleBeingBuiltOpt.GetMethodBody(method) != null) + MethodSymbol method = new SynthesizedStaticConstructor(sourceTypeSymbol); + if (PassesFilter(_filterOpt, method)) { - _moduleBeingBuiltOpt.AddSynthesizedDefinition(sourceTypeSymbol, method.GetCciAdapter()); + CompileMethod(method, -1, ref processedStaticInitializers, synthesizedSubmissionFields, compilationState); + + // If this method has been successfully built, we emit it. + if (_moduleBeingBuiltOpt.GetMethodBody(method) != null) + { + _moduleBeingBuiltOpt.AddSynthesizedDefinition(sourceTypeSymbol, method.GetCciAdapter()); + } } } - } - // If there is no explicit or implicit .cctor and no static initializers, then report - // warnings for any static non-nullable fields. (If there is no .cctor, there - // shouldn't be any initializers but for robustness, we check both.) - if (!hasStaticConstructor && - processedStaticInitializers.BoundInitializers.IsDefaultOrEmpty && - _compilation.LanguageVersion >= MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion() && - containingType is { IsImplicitlyDeclared: false, TypeKind: TypeKind.Class or TypeKind.Struct or TypeKind.Interface } && - ReportNullableDiagnostics) - { - NullableWalker.AnalyzeIfNeeded( - this._compilation, - new SynthesizedStaticConstructor(containingType), - GetSynthesizedEmptyBody(containingType), - _diagnostics.DiagnosticBag, - useConstructorExitWarnings: true, - initialNullableState: null, - getFinalNullableState: false, - finalNullableState: out _); + // If there is no explicit or implicit .cctor and no static initializers, then report + // warnings for any static non-nullable fields. (If there is no .cctor, there + // shouldn't be any initializers but for robustness, we check both.) + if (processedStaticInitializers.BoundInitializers.IsDefaultOrEmpty && + _compilation.LanguageVersion >= MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion() && + containingType is { IsImplicitlyDeclared: false, TypeKind: TypeKind.Class or TypeKind.Struct or TypeKind.Interface } && + ReportNullableDiagnostics) + { + NullableWalker.AnalyzeIfNeeded( + this._compilation, + new SynthesizedStaticConstructor(containingType), + GetSynthesizedEmptyBody(containingType), + _diagnostics.DiagnosticBag, + useConstructorExitWarnings: true, + initialNullableState: null, + getFinalNullableState: false, + finalNullableState: out _); + } } // compile submission constructor last so that synthesized submission fields are collected from all script methods: @@ -747,6 +739,14 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) stateMachine = stateMachine ?? asyncStateMachine; } + var factory = new SyntheticBoundNodeFactory(method, methodWithBody.Body.Syntax, compilationState, diagnosticsThisMethod); + var nullCheckStatements = LocalRewriter.ConstructNullCheckedStatementList(method.Parameters, factory); + if (!nullCheckStatements.IsEmpty) + { + loweredBody = factory.StatementList(nullCheckStatements.Concat(loweredBody)); + } + SetGlobalErrorIfTrue(nullCheckStatements.HasErrors() || diagnosticsThisMethod.HasAnyErrors()); + if (_emitMethodBodies && !diagnosticsThisMethod.HasAnyErrors() && !_globalHasErrors) { emittedBody = GenerateMethodBody( @@ -1288,27 +1288,19 @@ forSemanticModel.Syntax is { } semanticModelSyntax && if (hasBody) { - boundStatements = boundStatements.Concat(ImmutableArray.Create(loweredBodyOpt)); + boundStatements = boundStatements.Concat(loweredBodyOpt); } var factory = new SyntheticBoundNodeFactory(methodSymbol, syntax, compilationState, diagsForCurrentMethod); - // Iterators handled in IteratorRewriter.cs - if (!methodSymbol.IsIterator) + var nullCheckStatements = LocalRewriter.ConstructNullCheckedStatementList(methodSymbol.Parameters, factory); + boundStatements = nullCheckStatements.Concat(boundStatements); + hasErrors = nullCheckStatements.HasErrors() || diagsForCurrentMethod.HasAnyErrors(); + SetGlobalErrorIfTrue(hasErrors); + if (hasErrors) { - var boundStatementsWithNullCheck = LocalRewriter.TryConstructNullCheckedStatementList(methodSymbol.Parameters, boundStatements, factory); - - if (!boundStatementsWithNullCheck.IsDefault) - { - boundStatements = boundStatementsWithNullCheck; - hasErrors = boundStatementsWithNullCheck.HasErrors() || diagsForCurrentMethod.HasAnyErrors(); - SetGlobalErrorIfTrue(hasErrors); - if (hasErrors) - { - _diagnostics.AddRange(diagsForCurrentMethod); - return; - } - } + _diagnostics.AddRange(diagsForCurrentMethod); + return; } } if (_emitMethodBodies && (!(methodSymbol is SynthesizedStaticConstructor cctor) || cctor.ShouldEmit(processedInitializers.BoundInitializers))) diff --git a/src/Compilers/CSharp/Portable/Compiler/TypeCompilationState.cs b/src/Compilers/CSharp/Portable/Compiler/TypeCompilationState.cs index 9ed8097b9bfca..ac4d6ddcde519 100644 --- a/src/Compilers/CSharp/Portable/Compiler/TypeCompilationState.cs +++ b/src/Compilers/CSharp/Portable/Compiler/TypeCompilationState.cs @@ -71,6 +71,8 @@ internal MethodWithBody(MethodSymbol method, BoundStatement body, ImportChain? i public SynthesizedClosureEnvironment? StaticLambdaFrame; + public DelegateCacheContainer? ConcreteDelegateCacheContainer; + /// /// A graph of method->method references for this(...) constructor initializers. /// Used to detect and report initializer cycles. diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs index 0fa5603c6d141..c9f41c978e759 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs @@ -26,7 +26,8 @@ internal sealed class CSharpSymbolMatcher : SymbolMatcher public CSharpSymbolMatcher( IReadOnlyDictionary anonymousTypeMap, - IReadOnlyDictionary synthesizedDelegates, + IReadOnlyDictionary anonymousDelegates, + IReadOnlyDictionary anonymousDelegatesWithFixedTypes, SourceAssemblySymbol sourceAssembly, EmitContext sourceContext, SourceAssemblySymbol otherAssembly, @@ -34,12 +35,13 @@ public CSharpSymbolMatcher( ImmutableDictionary> otherSynthesizedMembersOpt) { _defs = new MatchDefsToSource(sourceContext, otherContext); - _symbols = new MatchSymbols(anonymousTypeMap, synthesizedDelegates, sourceAssembly, otherAssembly, otherSynthesizedMembersOpt, new DeepTranslator(otherAssembly.GetSpecialType(SpecialType.System_Object))); + _symbols = new MatchSymbols(anonymousTypeMap, anonymousDelegates, anonymousDelegatesWithFixedTypes, sourceAssembly, otherAssembly, otherSynthesizedMembersOpt, new DeepTranslator(otherAssembly.GetSpecialType(SpecialType.System_Object))); } public CSharpSymbolMatcher( IReadOnlyDictionary anonymousTypeMap, - IReadOnlyDictionary synthesizedDelegates, + IReadOnlyDictionary anonymousDelegates, + IReadOnlyDictionary anonymousDelegatesWithFixedTypes, SourceAssemblySymbol sourceAssembly, EmitContext sourceContext, PEAssemblySymbol otherAssembly) @@ -48,7 +50,8 @@ public CSharpSymbolMatcher( _symbols = new MatchSymbols( anonymousTypeMap, - synthesizedDelegates, + anonymousDelegates, + anonymousDelegatesWithFixedTypes, sourceAssembly, otherAssembly, otherSynthesizedMembers: null, @@ -276,7 +279,8 @@ public MatchDefsToSource( private sealed class MatchSymbols : CSharpSymbolVisitor { private readonly IReadOnlyDictionary _anonymousTypeMap; - private readonly IReadOnlyDictionary _synthesizedDelegates; + private readonly IReadOnlyDictionary _anonymousDelegates; + private readonly IReadOnlyDictionary _anonymousDelegatesWithFixedTypes; private readonly SourceAssemblySymbol _sourceAssembly; // metadata or source assembly: @@ -301,14 +305,16 @@ private sealed class MatchSymbols : CSharpSymbolVisitor public MatchSymbols( IReadOnlyDictionary anonymousTypeMap, - IReadOnlyDictionary synthesizedDelegates, + IReadOnlyDictionary anonymousDelegates, + IReadOnlyDictionary anonymousDelegatesWithFixedTypes, SourceAssemblySymbol sourceAssembly, AssemblySymbol otherAssembly, ImmutableDictionary>? otherSynthesizedMembers, DeepTranslator? deepTranslator) { _anonymousTypeMap = anonymousTypeMap; - _synthesizedDelegates = synthesizedDelegates; + _anonymousDelegates = anonymousDelegates; + _anonymousDelegatesWithFixedTypes = anonymousDelegatesWithFixedTypes; _sourceAssembly = sourceAssembly; _otherAssembly = otherAssembly; _otherSynthesizedMembers = otherSynthesizedMembers; @@ -528,17 +534,25 @@ public override Symbol VisitDynamicType(DynamicTypeSymbol symbol) switch (otherContainer.Kind) { case SymbolKind.Namespace: - if (sourceType is AnonymousTypeManager.AnonymousTypeTemplateSymbol template) + if (sourceType is AnonymousTypeManager.AnonymousTypeTemplateSymbol typeTemplate) { Debug.Assert((object)otherContainer == (object)_otherAssembly.GlobalNamespace); - TryFindAnonymousType(template, out var value); + TryFindAnonymousType(typeTemplate, out var value); return (NamedTypeSymbol?)value.Type?.GetInternalSymbol(); } - else if (sourceType is SynthesizedDelegateSymbol delegateSymbol) + else if (sourceType is AnonymousTypeManager.AnonymousDelegateTemplateSymbol delegateTemplate) { Debug.Assert((object)otherContainer == (object)_otherAssembly.GlobalNamespace); - TryFindSynthesizedDelegate(delegateSymbol, out var value); - return (NamedTypeSymbol?)value.Delegate?.GetInternalSymbol(); + if (delegateTemplate.HasFixedTypes) + { + TryFindAnonymousDelegateWithFixedType(delegateTemplate, out var value); + return (NamedTypeSymbol?)value.Type?.GetInternalSymbol(); + } + else + { + TryFindAnonymousDelegate(delegateTemplate, out var value); + return (NamedTypeSymbol?)value.Delegate?.GetInternalSymbol(); + } } if (sourceType.IsAnonymousType) @@ -662,12 +676,55 @@ internal bool TryFindAnonymousType(AnonymousTypeManager.AnonymousTypeTemplateSym return _anonymousTypeMap.TryGetValue(type.GetAnonymousTypeKey(), out otherType); } - internal bool TryFindSynthesizedDelegate(SynthesizedDelegateSymbol delegateSymbol, out SynthesizedDelegateValue otherDelegateSymbol) + internal bool TryFindAnonymousDelegate(AnonymousTypeManager.AnonymousDelegateTemplateSymbol delegateSymbol, out SynthesizedDelegateValue otherDelegateSymbol) { Debug.Assert((object)delegateSymbol.ContainingSymbol == (object)_sourceAssembly.GlobalNamespace); var key = new SynthesizedDelegateKey(delegateSymbol.MetadataName); - return _synthesizedDelegates.TryGetValue(key, out otherDelegateSymbol); + return _anonymousDelegates.TryGetValue(key, out otherDelegateSymbol); + } + + internal bool TryFindAnonymousDelegateWithFixedType(AnonymousTypeManager.AnonymousDelegateTemplateSymbol type, out AnonymousTypeValue otherType) + { + Debug.Assert((object)type.ContainingSymbol == (object)_sourceAssembly.GlobalNamespace); + + // Anonymous delegates with fixed types are indexed by name, and the names are <>f__AnonymousDelegate0, 1, ... . + // Within a compilation, the index in the name is determined by source order, but the actual signature + // of the delegate type may change between generations. For instance, the signature of a lambda + // expression may have been changed explicitly, or another lambda expression may have been inserted + // ahead of this one in source order. Therefore, we need to verify the signatures of the delegate types + // are equivalent - by comparing the Invoke() method signatures. + if (_anonymousDelegatesWithFixedTypes.TryGetValue(type.Name, out otherType) && + otherType.Type.GetInternalSymbol() is NamedTypeSymbol otherDelegateType && + isCorrespondingAnonymousDelegate(type, otherDelegateType)) + { + return true; + } + + otherType = default; + return false; + + bool isCorrespondingAnonymousDelegate(NamedTypeSymbol type, NamedTypeSymbol otherType) + { + if (type.Arity != otherType.Arity) + { + return false; + } + + type = SubstituteTypeParameters(type); + otherType = SubstituteTypeParameters(otherType); + + return type.DelegateInvokeMethod is { } invokeMethod && + otherType.DelegateInvokeMethod is { } otherInvokeMethod && + invokeMethod.Parameters.SequenceEqual(otherInvokeMethod.Parameters, (x, y) => isCorrespondingType(x.TypeWithAnnotations, y.TypeWithAnnotations)) && + isCorrespondingType(invokeMethod.ReturnTypeWithAnnotations, otherInvokeMethod.ReturnTypeWithAnnotations); + } + + bool isCorrespondingType(TypeWithAnnotations type, TypeWithAnnotations expectedType) + { + var otherType = type.WithTypeAndModifiers((TypeSymbol?)this.Visit(type.Type), this.VisitCustomModifiers(type.CustomModifiers)); + return otherType.Equals(expectedType, TypeCompareKind.CLRSignatureCompareOptions); + } } private Symbol? VisitNamedTypeMember(T member, Func predicate) @@ -768,6 +825,20 @@ private bool AreNamedTypesEqual(NamedTypeSymbol type, NamedTypeSymbol other) return type.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.SequenceEqual(other.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics, AreTypesEqual); } + private static NamedTypeSymbol SubstituteTypeParameters(NamedTypeSymbol type) + { + Debug.Assert(type.IsDefinition); + + var typeParameters = type.TypeParameters; + int n = typeParameters.Length; + if (n == 0) + { + return type; + } + + return type.Construct(IndexedTypeParameterSymbol.Take(n)); + } + private bool AreNamespacesEqual(NamespaceSymbol @namespace, NamespaceSymbol other) { Debug.Assert(StringOrdinalComparer.Equals(@namespace.MetadataName, other.MetadataName)); diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs index d996f499c3086..acf88a850bc11 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.IO; +using System.Linq; using System.Reflection.Metadata; using System.Threading; using Microsoft.CodeAnalysis.CodeGen; @@ -82,25 +83,32 @@ internal static EmitDifferenceResult EmitDifference( filterOpt: s => changes.RequiresCompilation(s.GetISymbol()), cancellationToken: cancellationToken)) { - // Map the definitions from the previous compilation to the current compilation. - // This must be done after compiling above since synthesized definitions - // (generated when compiling method bodies) may be required. - var mappedBaseline = MapToCompilation(compilation, moduleBeingBuilt); - - newBaseline = compilation.SerializeToDeltaStreams( - moduleBeingBuilt, - mappedBaseline, - definitionMap, - changes, - metadataStream, - ilStream, - pdbStream, - updatedMethods, - changedTypes, - diagnostics, - testData?.SymWriterFactory, - emitOptions.PdbFilePath, - cancellationToken); + if (!ContainsPreviousAnonymousDelegates(definitionMap, baseline.AnonymousDelegatesWithFixedTypes, moduleBeingBuilt.GetAnonymousDelegatesWithFixedTypes())) + { + diagnostics.Add(ErrorCode.ERR_EncUpdateFailedDelegateTypeChanged, Location.None); + } + else + { + // Map the definitions from the previous compilation to the current compilation. + // This must be done after compiling above since synthesized definitions + // (generated when compiling method bodies) may be required. + var mappedBaseline = MapToCompilation(compilation, moduleBeingBuilt); + + newBaseline = compilation.SerializeToDeltaStreams( + moduleBeingBuilt, + mappedBaseline, + definitionMap, + changes, + metadataStream, + ilStream, + pdbStream, + updatedMethods, + changedTypes, + diagnostics, + testData?.SymWriterFactory, + emitOptions.PdbFilePath, + cancellationToken); + } } return new EmitDifferenceResult( @@ -111,6 +119,37 @@ internal static EmitDifferenceResult EmitDifference( changedTypes: changedTypes.ToImmutableAndFree()); } + private static bool ContainsPreviousAnonymousDelegates( + CSharpDefinitionMap definitionMap, + IReadOnlyDictionary previousDictionary, + IReadOnlyDictionary currentDictionary) + { + if (previousDictionary.Count == 0) + { + return true; + } + + if (previousDictionary.Count > currentDictionary.Count) + { + return false; + } + + Dictionary currentTypes = getTypes(currentDictionary).ToDictionary(t => getName(t)); + IEnumerable previousTypes = getTypes(previousDictionary); + foreach (var previousType in previousTypes) + { + if (!currentTypes.TryGetValue(getName(previousType), out var currentType) || + definitionMap.MapDefinition(currentType) is null) + { + return false; + } + } + return true; + + static IEnumerable getTypes(IReadOnlyDictionary dictionary) => dictionary.Values.Select(v => v.Type); + static string getName(Cci.ITypeDefinition type) => ((Cci.INamedEntity)type).Name!; + } + /// /// Return a version of the baseline with all definitions mapped to this compilation. /// Definitions from the initial generation, from metadata, are not mapped since @@ -140,14 +179,16 @@ private static EmitBaseline MapToCompilation( // Mapping from previous compilation to the current. var anonymousTypeMap = moduleBeingBuilt.GetAnonymousTypeMap(); - var synthesizedDelegates = moduleBeingBuilt.GetSynthesizedDelegates(); + var anonymousDelegates = moduleBeingBuilt.GetAnonymousDelegates(); + var anonymousDelegatesWithFixedTypes = moduleBeingBuilt.GetAnonymousDelegatesWithFixedTypes(); var sourceAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly; var sourceContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); var otherContext = new EmitContext(moduleBeingBuilt, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); var matcher = new CSharpSymbolMatcher( anonymousTypeMap, - synthesizedDelegates, + anonymousDelegates, + anonymousDelegatesWithFixedTypes, sourceAssembly, sourceContext, compilation.SourceAssembly, @@ -159,7 +200,8 @@ private static EmitBaseline MapToCompilation( // TODO: can we reuse some data from the previous matcher? var matcherWithAllSynthesizedMembers = new CSharpSymbolMatcher( anonymousTypeMap, - synthesizedDelegates, + anonymousDelegates, + anonymousDelegatesWithFixedTypes, sourceAssembly, sourceContext, compilation.SourceAssembly, diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs index f3f674f209c65..efcb150be20da 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs @@ -47,7 +47,13 @@ public PEDeltaAssemblyBuilder( var metadataDecoder = (MetadataDecoder)metadataSymbols.MetadataDecoder; var metadataAssembly = (PEAssemblySymbol)metadataDecoder.ModuleSymbol.ContainingAssembly; - var matchToMetadata = new CSharpSymbolMatcher(metadataSymbols.AnonymousTypes, metadataSymbols.SynthesizedDelegates, sourceAssembly, context, metadataAssembly); + var matchToMetadata = new CSharpSymbolMatcher( + metadataSymbols.AnonymousTypes, + metadataSymbols.AnonymousDelegates, + metadataSymbols.AnonymousDelegatesWithFixedTypes, + sourceAssembly, + context, + metadataAssembly); CSharpSymbolMatcher? matchToPrevious = null; if (previousGeneration.Ordinal > 0) @@ -60,7 +66,8 @@ public PEDeltaAssemblyBuilder( matchToPrevious = new CSharpSymbolMatcher( previousGeneration.AnonymousTypeMap, - previousGeneration.SynthesizedDelegates, + previousGeneration.AnonymousDelegates, + previousGeneration.AnonymousDelegatesWithFixedTypes, sourceAssembly: sourceAssembly, sourceContext: context, otherAssembly: previousAssembly, @@ -116,21 +123,29 @@ private static EmitBaseline.MetadataSymbols GetOrCreateMetadataSymbols(EmitBasel ImmutableDictionary assemblyReferenceIdentityMap; var metadataAssembly = metadataCompilation.GetBoundReferenceManager().CreatePEAssemblyForAssemblyMetadata(AssemblyMetadata.Create(originalMetadata), MetadataImportOptions.All, out assemblyReferenceIdentityMap); var metadataDecoder = new MetadataDecoder(metadataAssembly.PrimaryModule); - var metadataAnonymousTypes = GetAnonymousTypeMapFromMetadata(originalMetadata.MetadataReader, metadataDecoder); - var metadataSynthesizedDelegates = GetSynthesizedDelegateMapFromMetadata(originalMetadata.MetadataReader, metadataDecoder); - var metadataSymbols = new EmitBaseline.MetadataSymbols(metadataAnonymousTypes, metadataSynthesizedDelegates, metadataDecoder, assemblyReferenceIdentityMap); + GetAnonymousTypeMapFromMetadata(originalMetadata.MetadataReader, metadataDecoder, out var metadataAnonymousTypes, out var metadataAnonymousDelegatesWithFixedTypes); + var metadataAnonymousDelegates = GetAnonymousDelegateMapFromMetadata(originalMetadata.MetadataReader, metadataDecoder); + var metadataSymbols = new EmitBaseline.MetadataSymbols(metadataAnonymousTypes, metadataAnonymousDelegates, metadataAnonymousDelegatesWithFixedTypes, metadataDecoder, assemblyReferenceIdentityMap); return InterlockedOperations.Initialize(ref initialBaseline.LazyMetadataSymbols, metadataSymbols); } // internal for testing - internal static IReadOnlyDictionary GetAnonymousTypeMapFromMetadata(MetadataReader reader, MetadataDecoder metadataDecoder) + internal static void GetAnonymousTypeMapFromMetadata( + MetadataReader reader, + MetadataDecoder metadataDecoder, + out IReadOnlyDictionary anonymousTypes, + out IReadOnlyDictionary anonymousDelegatesWithFixedTypes) { // In general, the anonymous type name is "<{module-id}>f__AnonymousType{index}#{submission-index}", // but EnC is not supported for modules nor submissions. Hence we only look for type names with no module id and no submission index. - const string AnonymousNameWithoutModulePrefix = "<>f__AnonymousType"; + const string AnonymousTypeOrDelegateNamePrefix = "<>f__Anonymous"; + const string AnonymousTypeNameWithoutModulePrefix = AnonymousTypeOrDelegateNamePrefix + "Type"; + const string AnonymousDelegateNameWithoutModulePrefix = AnonymousTypeOrDelegateNamePrefix + "Delegate"; + + var types = new Dictionary(); + var delegates = new Dictionary(); - var result = new Dictionary(); foreach (var handle in reader.TypeDefinitions) { var def = reader.GetTypeDefinition(handle); @@ -139,7 +154,7 @@ internal static IReadOnlyDictionary GetAno continue; } - if (!reader.StringComparer.StartsWith(def.Name, AnonymousNameWithoutModulePrefix)) + if (!reader.StringComparer.StartsWith(def.Name, AnonymousTypeOrDelegateNamePrefix)) { continue; } @@ -147,27 +162,38 @@ internal static IReadOnlyDictionary GetAno var metadataName = reader.GetString(def.Name); var name = MetadataHelpers.InferTypeArityAndUnmangleMetadataName(metadataName, out _); - if (name.StartsWith(AnonymousNameWithoutModulePrefix, StringComparison.Ordinal) && - int.TryParse(name.Substring(AnonymousNameWithoutModulePrefix.Length), NumberStyles.None, CultureInfo.InvariantCulture, out int index)) + if (name.StartsWith(AnonymousTypeNameWithoutModulePrefix, StringComparison.Ordinal)) + { + if (int.TryParse(name.Substring(AnonymousTypeNameWithoutModulePrefix.Length), NumberStyles.None, CultureInfo.InvariantCulture, out int index)) + { + var builder = ArrayBuilder.GetInstance(); + if (TryGetAnonymousTypeKey(reader, def, builder)) + { + var type = (NamedTypeSymbol)metadataDecoder.GetTypeOfToken(handle); + var key = new AnonymousTypeKey(builder.ToImmutable()); + var value = new AnonymousTypeValue(name, index, type.GetCciAdapter()); + types.Add(key, value); + } + builder.Free(); + } + } + else if (name.StartsWith(AnonymousDelegateNameWithoutModulePrefix, StringComparison.Ordinal)) { - var builder = ArrayBuilder.GetInstance(); - if (TryGetAnonymousTypeKey(reader, def, builder)) + if (int.TryParse(name.Substring(AnonymousDelegateNameWithoutModulePrefix.Length), NumberStyles.None, CultureInfo.InvariantCulture, out int index)) { var type = (NamedTypeSymbol)metadataDecoder.GetTypeOfToken(handle); - var key = new AnonymousTypeKey(builder.ToImmutable()); var value = new AnonymousTypeValue(name, index, type.GetCciAdapter()); - result.Add(key, value); + delegates.Add(name, value); } - - builder.Free(); } } - return result; + anonymousTypes = types; + anonymousDelegatesWithFixedTypes = delegates; } // internal for testing - internal static IReadOnlyDictionary GetSynthesizedDelegateMapFromMetadata(MetadataReader reader, MetadataDecoder metadataDecoder) + internal static IReadOnlyDictionary GetAnonymousDelegateMapFromMetadata(MetadataReader reader, MetadataDecoder metadataDecoder) { var result = new Dictionary(); foreach (var handle in reader.TypeDefinitions) @@ -238,12 +264,20 @@ public IReadOnlyDictionary GetAnonymousTyp return anonymousTypes; } - public IReadOnlyDictionary GetSynthesizedDelegates() + public IReadOnlyDictionary GetAnonymousDelegates() + { + var anonymousDelegates = this.Compilation.AnonymousTypeManager.GetAnonymousDelegates(); + // Should contain all entries in previous generation. + Debug.Assert(_previousGeneration.AnonymousDelegates.All(p => anonymousDelegates.ContainsKey(p.Key))); + return anonymousDelegates; + } + + public IReadOnlyDictionary GetAnonymousDelegatesWithFixedTypes() { - var synthesizedDelegates = this.Compilation.AnonymousTypeManager.GetSynthesizedDelegates(); + var anonymousDelegates = this.Compilation.AnonymousTypeManager.GetAnonymousDelegatesWithFixedTypes(); // Should contain all entries in previous generation. - Debug.Assert(_previousGeneration.SynthesizedDelegates.All(p => synthesizedDelegates.ContainsKey(p.Key))); - return synthesizedDelegates; + Debug.Assert(_previousGeneration.AnonymousDelegatesWithFixedTypes.All(p => anonymousDelegates.ContainsKey(p.Key))); + return anonymousDelegates; } public override IEnumerable GetTopLevelTypeDefinitions(EmitContext context) @@ -274,9 +308,9 @@ internal override ImmutableArray GetPreviousAnonymousTypes() return ImmutableArray.CreateRange(_previousGeneration.AnonymousTypeMap.Keys); } - internal override ImmutableArray GetPreviousSynthesizedDelegates() + internal override ImmutableArray GetPreviousAnonymousDelegates() { - return ImmutableArray.CreateRange(_previousGeneration.SynthesizedDelegates.Keys); + return ImmutableArray.CreateRange(_previousGeneration.AnonymousDelegates.Keys); } internal override int GetNextAnonymousTypeIndex() diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index b64be1556d300..e7344972930ab 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -497,7 +497,7 @@ internal virtual ImmutableArray GetPreviousAnonymousTypes() return ImmutableArray.Empty; } - internal virtual ImmutableArray GetPreviousSynthesizedDelegates() + internal virtual ImmutableArray GetPreviousAnonymousDelegates() { return ImmutableArray.Empty; } diff --git a/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs b/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs index 2362945a2ba54..2fb39014cd600 100644 --- a/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs +++ b/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs @@ -589,6 +589,12 @@ protected override EmbeddedType GetEmbeddedTypeForMember(SymbolAdapter member, S Debug.Assert(member.AdaptedSymbol.IsDefinition); Debug.Assert(ModuleBeingBuilt.SourceModule.AnyReferencedAssembliesAreLinked); + if (member.AdaptedSymbol.OriginalDefinition is SynthesizedGlobalMethodSymbol) + { + // No need to embed an internal type from current assembly + return null; + } + NamedTypeSymbol namedType = member.AdaptedSymbol.ContainingType; if (IsValidEmbeddableType(namedType, syntaxNodeOpt, diagnostics, this)) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 548dcc4ff83fe..49c483065552b 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2018,14 +2018,33 @@ internal enum ErrorCode WRN_LowerCaseTypeName = 8981, ERR_RecordStructConstructorCallsDefaultConstructor = 8982, ERR_StructHasInitializersAndNoDeclaredConstructor = 8983, + ERR_EncUpdateFailedDelegateTypeChanged = 8984, - ERR_IncorrectNullCheckSyntax = 8990, + ERR_DiscardCannotBeNullChecked = 8990, ERR_MustNullCheckInImplementation = 8991, ERR_NonNullableValueTypeIsNullChecked = 8992, WRN_NullCheckedHasDefaultNull = 8993, - ERR_NullCheckingOnByRefParameter = 8994, + ERR_NullCheckingOnOutParameter = 8994, WRN_NullCheckingOnNullableType = 8995, + ERR_RawStringNotInDirectives = 8996, + ERR_UnterminatedRawString = 8997, + ERR_TooManyQuotesForRawString = 8998, + ERR_LineDoesNotStartWithSameWhitespace = 8999, + ERR_RawStringDelimiterOnOwnLine = 9000, + ERR_RawStringInVerbatimInterpolatedStrings = 9001, + ERR_RawStringMustContainContent = 9002, + ERR_LineContainsDifferentWhitespace = 9003, + + // raw interpolated string literals + ERR_NotEnoughQuotesForRawString = 9004, + ERR_NotEnoughCloseBracesForRawString = 9005, + ERR_TooManyOpenBracesForRawString = 9006, + ERR_TooManyCloseBracesForRawString = 9007, + + ERR_IllegalAtSequence = 9008, + ERR_StringMustStartWithQuoteCharacter = 9009, + #endregion // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) diff --git a/src/Compilers/CSharp/Portable/Errors/LazyMissingNonNullTypesContextDiagnosticInfo.cs b/src/Compilers/CSharp/Portable/Errors/LazyMissingNonNullTypesContextDiagnosticInfo.cs index b1dc76bfd644b..37fe0a89c5354 100644 --- a/src/Compilers/CSharp/Portable/Errors/LazyMissingNonNullTypesContextDiagnosticInfo.cs +++ b/src/Compilers/CSharp/Portable/Errors/LazyMissingNonNullTypesContextDiagnosticInfo.cs @@ -5,6 +5,7 @@ #nullable disable using System.Diagnostics; +using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; @@ -25,20 +26,32 @@ private LazyMissingNonNullTypesContextDiagnosticInfo(TypeWithAnnotations type, D _info = info; } - public static void AddAll(bool isNullableEnabled, bool isGeneratedCode, TypeWithAnnotations type, Location location, DiagnosticBag diagnostics) +#nullable enable + /// + /// A `?` annotation on a type that isn't a value type causes: + /// - an error before C# 8.0 + /// - a warning outside of a NonNullTypes context + /// + public static void AddAll(Binder binder, SyntaxToken questionToken, TypeWithAnnotations? type, DiagnosticBag diagnostics) { + var location = questionToken.GetLocation(); + var rawInfos = ArrayBuilder.GetInstance(); - GetRawDiagnosticInfos(isNullableEnabled, isGeneratedCode, (CSharpSyntaxTree)location.SourceTree, rawInfos); + GetRawDiagnosticInfos(binder, questionToken, rawInfos); foreach (var rawInfo in rawInfos) { - diagnostics.Add(new LazyMissingNonNullTypesContextDiagnosticInfo(type, rawInfo), location); + var info = (type.HasValue) ? new LazyMissingNonNullTypesContextDiagnosticInfo(type.Value, rawInfo) : rawInfo; + diagnostics.Add(info, location); } + rawInfos.Free(); } -#nullable enable - private static void GetRawDiagnosticInfos(bool isNullableEnabled, bool isGeneratedCode, CSharpSyntaxTree tree, ArrayBuilder infos) + private static void GetRawDiagnosticInfos(Binder binder, SyntaxToken questionToken, ArrayBuilder infos) { + Debug.Assert(questionToken.SyntaxTree != null); + var tree = (CSharpSyntaxTree)questionToken.SyntaxTree; + const MessageID featureId = MessageID.IDS_FeatureNullableReferenceTypes; var info = featureId.GetFeatureAvailabilityDiagnosticInfo(tree.Options); if (info is object) @@ -46,9 +59,9 @@ private static void GetRawDiagnosticInfos(bool isNullableEnabled, bool isGenerat infos.Add(info); } - if (!isNullableEnabled && info?.Severity != DiagnosticSeverity.Error) + if (info?.Severity != DiagnosticSeverity.Error && !binder.AreNullableAnnotationsEnabled(questionToken)) { - var code = isGeneratedCode + var code = tree.IsGeneratedCode(binder.Compilation.Options.SyntaxTreeOptionsProvider, CancellationToken.None) ? ErrorCode.WRN_MissingNonNullTypesContextForAnnotationInGeneratedCode : ErrorCode.WRN_MissingNonNullTypesContextForAnnotation; infos.Add(new CSDiagnosticInfo(code)); @@ -56,43 +69,10 @@ private static void GetRawDiagnosticInfos(bool isNullableEnabled, bool isGenerat } #nullable disable - private static bool IsNullableReference(TypeSymbol type) + internal static bool IsNullableReference(TypeSymbol type) => type is null || !(type.IsValueType || type.IsErrorType()); protected override DiagnosticInfo ResolveInfo() => IsNullableReference(_type.Type) ? _info : null; - - /// - /// A `?` annotation on a type that isn't a value type causes: - /// - an error before C# 8.0 - /// - a warning outside of a NonNullTypes context - /// - public static void ReportNullableReferenceTypesIfNeeded( - bool isNullableEnabled, - bool isGeneratedCode, - TypeWithAnnotations type, - Location location, - DiagnosticBag diagnostics) - { - if (IsNullableReference(type.Type)) - { - ReportNullableReferenceTypesIfNeeded(isNullableEnabled, isGeneratedCode, location, diagnostics); - } - } - - public static void ReportNullableReferenceTypesIfNeeded( - bool isNullableEnabled, - bool isGeneratedCode, - Location location, - DiagnosticBag diagnostics) - { - var rawInfos = ArrayBuilder.GetInstance(); - GetRawDiagnosticInfos(isNullableEnabled, isGeneratedCode, (CSharpSyntaxTree)location.SourceTree, rawInfos); - foreach (var rawInfo in rawInfos) - { - diagnostics.Add(rawInfo, location); - } - rawInfos.Free(); - } } } diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index f2f0381e2c0bf..71383420e7ad6 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -244,6 +244,9 @@ internal enum MessageID IDS_FeatureNewLinesInInterpolations = MessageBase + 12813, IDS_FeatureListPattern = MessageBase + 12814, IDS_ParameterNullChecking = MessageBase + 12815, + + IDS_FeatureCacheStaticMethodGroupConversion = MessageBase + 12816, + IDS_FeatureRawStringLiterals = MessageBase + 12817, } // Message IDs may refer to strings that need to be localized. @@ -353,11 +356,13 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) // PREFER reporting diagnostics in binding when diagnostics do not affect the shape of the syntax tree // C# preview features. + case MessageID.IDS_FeatureRawStringLiterals: case MessageID.IDS_FeatureStaticAbstractMembersInInterfaces: // semantic check case MessageID.IDS_FeatureGenericAttributes: // semantic check case MessageID.IDS_FeatureNewLinesInInterpolations: // semantic check case MessageID.IDS_FeatureListPattern: // semantic check case MessageID.IDS_FeatureRequiredMembers: // semantic check + case MessageID.IDS_FeatureCacheStaticMethodGroupConversion: // lowering check case MessageID.IDS_ParameterNullChecking: // syntax check return LanguageVersion.Preview; diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index 9515734437ab1..82b3f200ad694 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -947,7 +947,7 @@ public override BoundNode VisitIsPatternExpression(BoundIsPatternExpression node } VisitPattern(pattern); - var reachableLabels = node.DecisionDag.ReachableLabels; + var reachableLabels = node.ReachabilityDecisionDag.ReachableLabels; if (!reachableLabels.Contains(node.WhenTrueLabel)) { SetState(this.StateWhenFalse); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs index 67d7bf145a7ac..59029891d19b9 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs @@ -43,7 +43,7 @@ protected virtual TLocalState VisitSwitchStatementDispatch(BoundSwitchStatement TLocalState initialState = this.State.Clone(); - var reachableLabels = node.DecisionDag.ReachableLabels; + var reachableLabels = node.ReachabilityDecisionDag.ReachableLabels; foreach (var section in node.SwitchSections) { foreach (var label in section.SwitchLabels) @@ -71,7 +71,7 @@ protected virtual TLocalState VisitSwitchStatementDispatch(BoundSwitchStatement } TLocalState afterSwitchState = UnreachableState(); - if (node.DecisionDag.ReachableLabels.Contains(node.BreakLabel) || + if (node.ReachabilityDecisionDag.ReachableLabels.Contains(node.BreakLabel) || (node.DefaultLabel == null && node.Expression.ConstantValue == null && IsTraditionalSwitch(node))) { Join(ref afterSwitchState, ref initialState); @@ -157,7 +157,7 @@ private BoundNode VisitSwitchExpression(BoundSwitchExpression node) VisitRvalue(node.Expression); var dispatchState = this.State; var endState = UnreachableState(); - var reachableLabels = node.DecisionDag.ReachableLabels; + var reachableLabels = node.ReachabilityDecisionDag.ReachableLabels; foreach (var arm in node.SwitchArms) { SetState(dispatchState.Clone()); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs index 9661ded9d326e..45e47e130cc92 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - #if DEBUG // We use a struct rather than a class to represent the state for efficiency // for data flow analysis, with 32 bits of data inline. Merely copying the state @@ -59,7 +57,7 @@ internal partial class DefiniteAssignmentPass : LocalDataFlowPass< /// /// Some variables that should be considered initially assigned. Used for region analysis. /// - private readonly HashSet initiallyAssignedVariables; + private readonly HashSet? initiallyAssignedVariables; /// /// Variables that were used anywhere, in the sense required to suppress warnings about @@ -67,12 +65,10 @@ internal partial class DefiniteAssignmentPass : LocalDataFlowPass< /// private readonly PooledHashSet _usedVariables = PooledHashSet.GetInstance(); -#nullable enable /// /// Parameters of record primary constructors that were read anywhere. /// private PooledHashSet? _readParameters; -#nullable disable /// /// Variables that were used anywhere, in the sense required to suppress warnings about @@ -105,12 +101,12 @@ internal partial class DefiniteAssignmentPass : LocalDataFlowPass< /// /// The current source assembly. /// - private readonly SourceAssemblySymbol _sourceAssembly; + private readonly SourceAssemblySymbol? _sourceAssembly; /// /// A set of address-of expressions for which the operand is not definitely assigned. /// - private readonly HashSet _unassignedVariableAddressOfSyntaxes; + private readonly HashSet? _unassignedVariableAddressOfSyntaxes; /// /// Tracks variables for which we have already reported a definite assignment error. This @@ -136,7 +132,7 @@ internal partial class DefiniteAssignmentPass : LocalDataFlowPass< /// /// The topmost method of this analysis. /// - protected MethodSymbol topLevelMethod; + protected MethodSymbol? topLevelMethod; protected bool _convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = false; // By default, just let the original exception to bubble up. @@ -151,7 +147,7 @@ internal DefiniteAssignmentPass( BoundNode node, bool strictAnalysis, bool trackUnassignments = false, - HashSet unassignedVariableAddressOfSyntaxes = null, + HashSet? unassignedVariableAddressOfSyntaxes = null, bool requireOutParamsAssigned = true, bool trackClassFields = false, bool trackStaticMembers = false) @@ -160,7 +156,7 @@ internal DefiniteAssignmentPass( trackUnassignments) { this.initiallyAssignedVariables = null; - _sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly; + _sourceAssembly = GetSourceAssembly(compilation, member, node); _unassignedVariableAddressOfSyntaxes = unassignedVariableAddressOfSyntaxes; _requireOutParamsAssigned = requireOutParamsAssigned; _trackClassFields = trackClassFields; @@ -175,11 +171,11 @@ internal DefiniteAssignmentPass( BoundNode node, EmptyStructTypeCache emptyStructs, bool trackUnassignments = false, - HashSet initiallyAssignedVariables = null) + HashSet? initiallyAssignedVariables = null) : base(compilation, member, node, emptyStructs, trackUnassignments) { this.initiallyAssignedVariables = initiallyAssignedVariables; - _sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly; + _sourceAssembly = GetSourceAssembly(compilation, member, node); this.CurrentSymbol = member; _unassignedVariableAddressOfSyntaxes = null; _requireOutParamsAssigned = true; @@ -208,6 +204,26 @@ internal DefiniteAssignmentPass( _shouldCheckConverted = this.GetType() == typeof(DefiniteAssignmentPass); } + private static SourceAssemblySymbol? GetSourceAssembly( + CSharpCompilation compilation, + Symbol member, + BoundNode node) + { + if (member is null) + { + return null; + } + if (node.Kind == BoundKind.Attribute) + { + // member is the attribute type, not the symbol where the attribute is applied. + Debug.Assert(member is TypeSymbol type && + (type.IsErrorType() || compilation.IsAttributeType(type))); + return null; + } + Debug.Assert((object)member.ContainingAssembly == compilation?.SourceAssembly); + return member.ContainingAssembly as SourceAssemblySymbol; + } + protected override void Free() { variableBySlot.Free(); @@ -237,6 +253,7 @@ protected override int AddVariable(VariableIdentifier identifier) return slot; } +#nullable disable protected Symbol GetNonMemberSymbol(int slot) { VariableIdentifier variableId = variableBySlot[slot]; diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 3bdde539f9352..6ff752fbfba82 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -693,7 +693,8 @@ void checkMemberStateOnConstructorExit(MethodSymbol constructor, Symbol member, : NullableFlowState.MaybeNull; if (memberState >= badState) // is 'memberState' as bad as or worse than 'badState'? { - Diagnostics.Add(ErrorCode.WRN_UninitializedNonNullableField, exitLocation ?? symbol.Locations.FirstOrNone(), symbol.Kind.Localize(), symbol.Name); + var info = new CSDiagnosticInfo(ErrorCode.WRN_UninitializedNonNullableField, new object[] { symbol.Kind.Localize(), symbol.Name }, ImmutableArray.Empty, additionalLocations: symbol.Locations); + Diagnostics.Add(info, exitLocation ?? symbol.Locations.FirstOrNone()); } } @@ -2518,6 +2519,7 @@ private void EnterParameter(ParameterSymbol parameter, TypeWithAnnotations param useLegacyWarnings: false, trackMembers: false, assignmentKind: AssignmentKind.Assignment); + Unsplit(); // If the LHS has annotations, we perform an additional check for nullable value types CheckDisallowedNullAssignment(resultType, parameterAnnotations, equalsValue.Value.Syntax.Location); @@ -3036,6 +3038,7 @@ private void DeclareLocals(ImmutableArray locals) else { valueType = VisitOptionalImplicitConversion(initializer, targetTypeOpt: inferredType ? default : type, useLegacyWarnings: true, trackMembers: true, AssignmentKind.Assignment); + Unsplit(); } if (inferredType) @@ -3599,6 +3602,7 @@ int getOrCreateSlot(int containingSlot, Symbol symbol) conversionCompletion is not null ? (conversionCompletion(type), null) : VisitOptionalImplicitConversion(node.Right, type, useLegacyWarnings: false, trackMembers: true, AssignmentKind.Assignment, delayCompletionForType); + Unsplit(); if (delayCompletionForType) { @@ -3896,6 +3900,7 @@ private int GetOrCreatePlaceholderSlot(object identifier, TypeWithAnnotations ty foreach (var expr in expressions) { _ = VisitOptionalImplicitConversion(expr, elementType, useLegacyWarnings: false, trackMembers: false, AssignmentKind.Assignment); + Unsplit(); } } else @@ -4355,25 +4360,26 @@ private void ReinferBinaryOperatorAndSetResult( // Analyze operator call properly (honoring [Disallow|Allow|Maybe|NotNull] attribute annotations) https://github.com/dotnet/roslyn/issues/32671 var parameters = method.Parameters; - visitOperandConversion(binary.Left, leftOperand, leftConversion, parameters[0], leftUnderlyingType); - visitOperandConversion(binary.Right, rightOperand, rightConversion, parameters[1], rightUnderlyingType); + visitOperandConversionAndPostConditions(binary.Left, leftOperand, leftConversion, parameters[0], leftUnderlyingType); + visitOperandConversionAndPostConditions(binary.Right, rightOperand, rightConversion, parameters[1], rightUnderlyingType); SetUpdatedSymbol(binary, binary.Method!, method); - void visitOperandConversion( + void visitOperandConversionAndPostConditions( BoundExpression expr, BoundExpression operand, Conversion conversion, ParameterSymbol parameter, TypeWithState operandType) { - TypeWithAnnotations targetTypeWithNullability = parameter.TypeWithAnnotations; + var parameterAnnotations = GetParameterAnnotations(parameter); + var targetTypeWithNullability = ApplyLValueAnnotations(parameter.TypeWithAnnotations, parameterAnnotations); if (isLifted && targetTypeWithNullability.Type.IsNonNullableValueType()) { targetTypeWithNullability = TypeWithAnnotations.Create(MakeNullableOf(targetTypeWithNullability)); } - _ = VisitConversion( + var resultType = VisitConversion( expr as BoundConversion, operand, conversion, @@ -4384,6 +4390,9 @@ void visitOperandConversion( useLegacyWarnings: false, AssignmentKind.Argument, parameter); + CheckDisallowedNullAssignment(resultType, parameterAnnotations, expr.Syntax.Location, operand); + + LearnFromPostConditions(operand, parameterAnnotations); } } else @@ -6403,7 +6412,7 @@ private void VisitArgumentOutboundAssignmentsAndPostConditions( case RefKind.In: { // learn from post-conditions [Maybe/NotNull, Maybe/NotNullWhen] without using an assignment - learnFromPostConditions(argument, parameterType, parameterAnnotations); + LearnFromPostConditions(argument, parameterAnnotations); } break; case RefKind.Ref: @@ -6586,50 +6595,53 @@ static TypeWithState applyPostConditionsWhenFalse(TypeWithState typeWithState, F return typeWithState; } + } - void learnFromPostConditions(BoundExpression argument, TypeWithAnnotations parameterType, FlowAnalysisAnnotations parameterAnnotations) - { - // Note: NotNull = NotNullWhen(true) + NotNullWhen(false) - bool notNullWhenTrue = (parameterAnnotations & FlowAnalysisAnnotations.NotNullWhenTrue) != 0; - bool notNullWhenFalse = (parameterAnnotations & FlowAnalysisAnnotations.NotNullWhenFalse) != 0; + /// + /// Learn from postconditions on a by-value or 'in' argument. + /// + private void LearnFromPostConditions(BoundExpression argument, FlowAnalysisAnnotations parameterAnnotations) + { + // Note: NotNull = NotNullWhen(true) + NotNullWhen(false) + bool notNullWhenTrue = (parameterAnnotations & FlowAnalysisAnnotations.NotNullWhenTrue) != 0; + bool notNullWhenFalse = (parameterAnnotations & FlowAnalysisAnnotations.NotNullWhenFalse) != 0; + + // Note: MaybeNull = MaybeNullWhen(true) + MaybeNullWhen(false) + bool maybeNullWhenTrue = (parameterAnnotations & FlowAnalysisAnnotations.MaybeNullWhenTrue) != 0; + bool maybeNullWhenFalse = (parameterAnnotations & FlowAnalysisAnnotations.MaybeNullWhenFalse) != 0; - // Note: MaybeNull = MaybeNullWhen(true) + MaybeNullWhen(false) - bool maybeNullWhenTrue = (parameterAnnotations & FlowAnalysisAnnotations.MaybeNullWhenTrue) != 0; - bool maybeNullWhenFalse = (parameterAnnotations & FlowAnalysisAnnotations.MaybeNullWhenFalse) != 0; + if (maybeNullWhenTrue && maybeNullWhenFalse && !IsConditionalState && !(notNullWhenTrue && notNullWhenFalse)) + { + LearnFromNullTest(argument, ref State); + } + else if (notNullWhenTrue && notNullWhenFalse + && !IsConditionalState + && !(maybeNullWhenTrue || maybeNullWhenFalse)) + { + LearnFromNonNullTest(argument, ref State); + } + else if (notNullWhenTrue || notNullWhenFalse || maybeNullWhenTrue || maybeNullWhenFalse) + { + Split(); - if (maybeNullWhenTrue && maybeNullWhenFalse && !IsConditionalState && !(notNullWhenTrue && notNullWhenFalse)) + if (notNullWhenTrue) { - LearnFromNullTest(argument, ref State); + LearnFromNonNullTest(argument, ref StateWhenTrue); } - else if (notNullWhenTrue && notNullWhenFalse - && !IsConditionalState - && !(maybeNullWhenTrue || maybeNullWhenFalse)) + + if (notNullWhenFalse) { - LearnFromNonNullTest(argument, ref State); + LearnFromNonNullTest(argument, ref StateWhenFalse); } - else if (notNullWhenTrue || notNullWhenFalse || maybeNullWhenTrue || maybeNullWhenFalse) - { - Split(); - - if (notNullWhenTrue) - { - LearnFromNonNullTest(argument, ref StateWhenTrue); - } - - if (notNullWhenFalse) - { - LearnFromNonNullTest(argument, ref StateWhenFalse); - } - if (maybeNullWhenTrue) - { - LearnFromNullTest(argument, ref StateWhenTrue); - } + if (maybeNullWhenTrue) + { + LearnFromNullTest(argument, ref StateWhenTrue); + } - if (maybeNullWhenFalse) - { - LearnFromNullTest(argument, ref StateWhenFalse); - } + if (maybeNullWhenFalse) + { + LearnFromNullTest(argument, ref StateWhenFalse); } } } @@ -8259,6 +8271,8 @@ private TypeWithState VisitUserDefinedConversion( fromExplicitCast: conversionOpt?.ExplicitCastInCode ?? false, diagnosticLocation); + LearnFromPostConditions(conversionOperand, parameterAnnotations); + TrackAnalyzedNullabilityThroughConversionGroup(operandType, conversionOpt, conversionOperand); return operandType; @@ -8755,6 +8769,7 @@ private void VisitThisOrBaseReference(BoundExpression node) { var discarded = left is BoundDiscardExpression; rightState = VisitOptionalImplicitConversion(right, targetTypeOpt: discarded ? default : leftLValueType, UseLegacyWarnings(left, leftLValueType), trackMembers: true, AssignmentKind.Assignment); + Unsplit(); } else { @@ -8936,7 +8951,7 @@ private void VisitDeconstructionArguments(ArrayBuilder v } else { - VisitTupleDeconstructionArguments(variables, conversion.DeconstructConversionInfo, right); + VisitTupleDeconstructionArguments(variables, conversion.DeconstructConversionInfo, right, rightResultOpt); } } @@ -9038,10 +9053,10 @@ private void VisitDeconstructMethodArguments(ArrayBuilder variables, ImmutableArray<(BoundValuePlaceholder? placeholder, BoundExpression? conversion)> deconstructConversionInfo, BoundExpression right) + private void VisitTupleDeconstructionArguments(ArrayBuilder variables, ImmutableArray<(BoundValuePlaceholder? placeholder, BoundExpression? conversion)> deconstructConversionInfo, BoundExpression right, TypeWithState? rightResultOpt) { int n = variables.Count; - var rightParts = GetDeconstructionRightParts(right); + var rightParts = GetDeconstructionRightParts(right, rightResultOpt); Debug.Assert(rightParts.Length == n); for (int i = 0; i < n; i++) @@ -9076,6 +9091,7 @@ private void VisitTupleDeconstructionArguments(ArrayBuilder - private ImmutableArray GetDeconstructionRightParts(BoundExpression expr) + private ImmutableArray GetDeconstructionRightParts(BoundExpression expr, TypeWithState? rightResultOpt) { switch (expr.Kind) { @@ -9184,11 +9200,15 @@ private ImmutableArray GetDeconstructionRightParts(BoundExpress { case ConversionKind.Identity: case ConversionKind.ImplicitTupleLiteral: - return GetDeconstructionRightParts(conv.Operand); + return GetDeconstructionRightParts(conv.Operand, null); } } break; } + if (rightResultOpt is { } rightResult) + { + expr = CreatePlaceholderIfNecessary(expr, rightResult.ToTypeWithAnnotations(compilation)); + } if (expr.Type is NamedTypeSymbol { IsTupleType: true } tupleType) { @@ -10737,6 +10757,7 @@ private void VisitThrow(BoundExpression? expr) method.ReturnType, errorLocation: null, diagnostics: null); _ = VisitOptionalImplicitConversion(expr, elementType, useLegacyWarnings: false, trackMembers: false, AssignmentKind.Return); + Unsplit(); return null; } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs index bf798cf0a94a6..ee1a38f5814de 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs @@ -254,7 +254,7 @@ protected override LocalState VisitSwitchStatementDispatch(BoundSwitchStatement Visit(node.Expression); var expressionState = ResultType; - var labelStateMap = LearnFromDecisionDag(node.Syntax, node.DecisionDag, node.Expression, expressionState, stateWhenNotNullOpt: null); + var labelStateMap = LearnFromDecisionDag(node.Syntax, node.ReachabilityDecisionDag, node.Expression, expressionState, stateWhenNotNullOpt: null); foreach (var section in node.SwitchSections) { foreach (var label in section.SwitchLabels) @@ -514,6 +514,7 @@ public PossiblyConditionalState Clone() var outputSlot = makeDagTempSlot(type, output); Debug.Assert(outputSlot > 0); addToTempMap(output, outputSlot, type.Type); + this.State[outputSlot] = NullableFlowState.NotNull; // Slice value is assumed to be never null break; } case BoundDagAssignmentEvaluation e: @@ -828,7 +829,7 @@ private void VisitSwitchExpressionCore(BoundSwitchExpression node, bool inferTyp Visit(node.Expression); var expressionState = ResultType; - var labelStateMap = LearnFromDecisionDag(node.Syntax, node.DecisionDag, node.Expression, expressionState, stateWhenNotNullOpt: null); + var labelStateMap = LearnFromDecisionDag(node.Syntax, node.ReachabilityDecisionDag, node.Expression, expressionState, stateWhenNotNullOpt: null); var endState = UnreachableState(); if (!node.ReportedNotExhaustive && node.DefaultLabel != null && @@ -836,7 +837,7 @@ private void VisitSwitchExpressionCore(BoundSwitchExpression node, bool inferTyp defaultLabelState.believedReachable) { SetState(defaultLabelState.state); - var nodes = node.DecisionDag.TopologicallySortedNodes; + var nodes = node.ReachabilityDecisionDag.TopologicallySortedNodes; var leaf = nodes.Where(n => n is BoundLeafDecisionDagNode leaf && leaf.Label == node.DefaultLabel).First(); var samplePattern = PatternExplainer.SamplePatternForPathToDagNode( BoundDagTemp.ForOriginalInput(node.Expression), nodes, leaf, nullPaths: true, out bool requiresFalseWhenClause, out _); @@ -984,7 +985,7 @@ public override BoundNode VisitIsPatternExpression(BoundIsPatternExpression node VisitPatternForRewriting(node.Pattern); var hasStateWhenNotNull = VisitPossibleConditionalAccess(node.Expression, out var conditionalStateWhenNotNull); var expressionState = ResultType; - var labelStateMap = LearnFromDecisionDag(node.Syntax, node.DecisionDag, node.Expression, expressionState, hasStateWhenNotNull ? conditionalStateWhenNotNull : null); + var labelStateMap = LearnFromDecisionDag(node.Syntax, node.ReachabilityDecisionDag, node.Expression, expressionState, hasStateWhenNotNull ? conditionalStateWhenNotNull : null); var trueState = labelStateMap.TryGetValue(node.IsNegated ? node.WhenFalseLabel : node.WhenTrueLabel, out var s1) ? s1.state : UnreachableState(); var falseState = labelStateMap.TryGetValue(node.IsNegated ? node.WhenTrueLabel : node.WhenFalseLabel, out var s2) ? s2.state : UnreachableState(); labelStateMap.Free(); diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index 27917beaaab63..234351a12b658 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -3638,22 +3638,22 @@ public BoundContinueStatement Update(GeneratedLabelSymbol label) internal sealed partial class BoundSwitchStatement : BoundStatement { - public BoundSwitchStatement(SyntaxNode syntax, BoundExpression expression, ImmutableArray innerLocals, ImmutableArray innerLocalFunctions, ImmutableArray switchSections, BoundDecisionDag decisionDag, BoundSwitchLabel? defaultLabel, GeneratedLabelSymbol breakLabel, bool hasErrors = false) - : base(BoundKind.SwitchStatement, syntax, hasErrors || expression.HasErrors() || switchSections.HasErrors() || decisionDag.HasErrors() || defaultLabel.HasErrors()) + public BoundSwitchStatement(SyntaxNode syntax, BoundExpression expression, ImmutableArray innerLocals, ImmutableArray innerLocalFunctions, ImmutableArray switchSections, BoundDecisionDag reachabilityDecisionDag, BoundSwitchLabel? defaultLabel, GeneratedLabelSymbol breakLabel, bool hasErrors = false) + : base(BoundKind.SwitchStatement, syntax, hasErrors || expression.HasErrors() || switchSections.HasErrors() || reachabilityDecisionDag.HasErrors() || defaultLabel.HasErrors()) { RoslynDebug.Assert(expression is object, "Field 'expression' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(!innerLocals.IsDefault, "Field 'innerLocals' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(!innerLocalFunctions.IsDefault, "Field 'innerLocalFunctions' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(!switchSections.IsDefault, "Field 'switchSections' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); - RoslynDebug.Assert(decisionDag is object, "Field 'decisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(reachabilityDecisionDag is object, "Field 'reachabilityDecisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(breakLabel is object, "Field 'breakLabel' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.Expression = expression; this.InnerLocals = innerLocals; this.InnerLocalFunctions = innerLocalFunctions; this.SwitchSections = switchSections; - this.DecisionDag = decisionDag; + this.ReachabilityDecisionDag = reachabilityDecisionDag; this.DefaultLabel = defaultLabel; this.BreakLabel = breakLabel; } @@ -3667,7 +3667,7 @@ public BoundSwitchStatement(SyntaxNode syntax, BoundExpression expression, Immut public ImmutableArray SwitchSections { get; } - public BoundDecisionDag DecisionDag { get; } + public BoundDecisionDag ReachabilityDecisionDag { get; } public BoundSwitchLabel? DefaultLabel { get; } @@ -3675,11 +3675,11 @@ public BoundSwitchStatement(SyntaxNode syntax, BoundExpression expression, Immut [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitSwitchStatement(this); - public BoundSwitchStatement Update(BoundExpression expression, ImmutableArray innerLocals, ImmutableArray innerLocalFunctions, ImmutableArray switchSections, BoundDecisionDag decisionDag, BoundSwitchLabel? defaultLabel, GeneratedLabelSymbol breakLabel) + public BoundSwitchStatement Update(BoundExpression expression, ImmutableArray innerLocals, ImmutableArray innerLocalFunctions, ImmutableArray switchSections, BoundDecisionDag reachabilityDecisionDag, BoundSwitchLabel? defaultLabel, GeneratedLabelSymbol breakLabel) { - if (expression != this.Expression || innerLocals != this.InnerLocals || innerLocalFunctions != this.InnerLocalFunctions || switchSections != this.SwitchSections || decisionDag != this.DecisionDag || defaultLabel != this.DefaultLabel || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(breakLabel, this.BreakLabel)) + if (expression != this.Expression || innerLocals != this.InnerLocals || innerLocalFunctions != this.InnerLocalFunctions || switchSections != this.SwitchSections || reachabilityDecisionDag != this.ReachabilityDecisionDag || defaultLabel != this.DefaultLabel || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(breakLabel, this.BreakLabel)) { - var result = new BoundSwitchStatement(this.Syntax, expression, innerLocals, innerLocalFunctions, switchSections, decisionDag, defaultLabel, breakLabel, this.HasErrors); + var result = new BoundSwitchStatement(this.Syntax, expression, innerLocals, innerLocalFunctions, switchSections, reachabilityDecisionDag, defaultLabel, breakLabel, this.HasErrors); result.CopyAttributes(this); return result; } @@ -4768,17 +4768,17 @@ public BoundConditionalGoto Update(BoundExpression condition, bool jumpIfTrue, L internal abstract partial class BoundSwitchExpression : BoundExpression { - protected BoundSwitchExpression(BoundKind kind, SyntaxNode syntax, BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag decisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol? type, bool hasErrors = false) + protected BoundSwitchExpression(BoundKind kind, SyntaxNode syntax, BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag reachabilityDecisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol? type, bool hasErrors = false) : base(kind, syntax, type, hasErrors) { RoslynDebug.Assert(expression is object, "Field 'expression' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(!switchArms.IsDefault, "Field 'switchArms' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); - RoslynDebug.Assert(decisionDag is object, "Field 'decisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(reachabilityDecisionDag is object, "Field 'reachabilityDecisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.Expression = expression; this.SwitchArms = switchArms; - this.DecisionDag = decisionDag; + this.ReachabilityDecisionDag = reachabilityDecisionDag; this.DefaultLabel = defaultLabel; this.ReportedNotExhaustive = reportedNotExhaustive; } @@ -4788,7 +4788,7 @@ protected BoundSwitchExpression(BoundKind kind, SyntaxNode syntax, BoundExpressi public ImmutableArray SwitchArms { get; } - public BoundDecisionDag DecisionDag { get; } + public BoundDecisionDag ReachabilityDecisionDag { get; } public LabelSymbol? DefaultLabel { get; } @@ -4840,24 +4840,24 @@ public BoundSwitchExpressionArm Update(ImmutableArray locals, Bound internal sealed partial class BoundUnconvertedSwitchExpression : BoundSwitchExpression { - public BoundUnconvertedSwitchExpression(SyntaxNode syntax, BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag decisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol? type, bool hasErrors = false) - : base(BoundKind.UnconvertedSwitchExpression, syntax, expression, switchArms, decisionDag, defaultLabel, reportedNotExhaustive, type, hasErrors || expression.HasErrors() || switchArms.HasErrors() || decisionDag.HasErrors()) + public BoundUnconvertedSwitchExpression(SyntaxNode syntax, BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag reachabilityDecisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol? type, bool hasErrors = false) + : base(BoundKind.UnconvertedSwitchExpression, syntax, expression, switchArms, reachabilityDecisionDag, defaultLabel, reportedNotExhaustive, type, hasErrors || expression.HasErrors() || switchArms.HasErrors() || reachabilityDecisionDag.HasErrors()) { RoslynDebug.Assert(expression is object, "Field 'expression' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(!switchArms.IsDefault, "Field 'switchArms' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); - RoslynDebug.Assert(decisionDag is object, "Field 'decisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(reachabilityDecisionDag is object, "Field 'reachabilityDecisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitUnconvertedSwitchExpression(this); - public BoundUnconvertedSwitchExpression Update(BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag decisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol? type) + public BoundUnconvertedSwitchExpression Update(BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag reachabilityDecisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol? type) { - if (expression != this.Expression || switchArms != this.SwitchArms || decisionDag != this.DecisionDag || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(defaultLabel, this.DefaultLabel) || reportedNotExhaustive != this.ReportedNotExhaustive || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (expression != this.Expression || switchArms != this.SwitchArms || reachabilityDecisionDag != this.ReachabilityDecisionDag || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(defaultLabel, this.DefaultLabel) || reportedNotExhaustive != this.ReportedNotExhaustive || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundUnconvertedSwitchExpression(this.Syntax, expression, switchArms, decisionDag, defaultLabel, reportedNotExhaustive, type, this.HasErrors); + var result = new BoundUnconvertedSwitchExpression(this.Syntax, expression, switchArms, reachabilityDecisionDag, defaultLabel, reportedNotExhaustive, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -4867,13 +4867,13 @@ public BoundUnconvertedSwitchExpression Update(BoundExpression expression, Immut internal sealed partial class BoundConvertedSwitchExpression : BoundSwitchExpression { - public BoundConvertedSwitchExpression(SyntaxNode syntax, TypeSymbol? naturalTypeOpt, bool wasTargetTyped, BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag decisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol type, bool hasErrors = false) - : base(BoundKind.ConvertedSwitchExpression, syntax, expression, switchArms, decisionDag, defaultLabel, reportedNotExhaustive, type, hasErrors || expression.HasErrors() || switchArms.HasErrors() || decisionDag.HasErrors()) + public BoundConvertedSwitchExpression(SyntaxNode syntax, TypeSymbol? naturalTypeOpt, bool wasTargetTyped, BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag reachabilityDecisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol type, bool hasErrors = false) + : base(BoundKind.ConvertedSwitchExpression, syntax, expression, switchArms, reachabilityDecisionDag, defaultLabel, reportedNotExhaustive, type, hasErrors || expression.HasErrors() || switchArms.HasErrors() || reachabilityDecisionDag.HasErrors()) { RoslynDebug.Assert(expression is object, "Field 'expression' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(!switchArms.IsDefault, "Field 'switchArms' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); - RoslynDebug.Assert(decisionDag is object, "Field 'decisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(reachabilityDecisionDag is object, "Field 'reachabilityDecisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.NaturalTypeOpt = naturalTypeOpt; @@ -4889,11 +4889,11 @@ public BoundConvertedSwitchExpression(SyntaxNode syntax, TypeSymbol? naturalType [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitConvertedSwitchExpression(this); - public BoundConvertedSwitchExpression Update(TypeSymbol? naturalTypeOpt, bool wasTargetTyped, BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag decisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol type) + public BoundConvertedSwitchExpression Update(TypeSymbol? naturalTypeOpt, bool wasTargetTyped, BoundExpression expression, ImmutableArray switchArms, BoundDecisionDag reachabilityDecisionDag, LabelSymbol? defaultLabel, bool reportedNotExhaustive, TypeSymbol type) { - if (!TypeSymbol.Equals(naturalTypeOpt, this.NaturalTypeOpt, TypeCompareKind.ConsiderEverything) || wasTargetTyped != this.WasTargetTyped || expression != this.Expression || switchArms != this.SwitchArms || decisionDag != this.DecisionDag || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(defaultLabel, this.DefaultLabel) || reportedNotExhaustive != this.ReportedNotExhaustive || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (!TypeSymbol.Equals(naturalTypeOpt, this.NaturalTypeOpt, TypeCompareKind.ConsiderEverything) || wasTargetTyped != this.WasTargetTyped || expression != this.Expression || switchArms != this.SwitchArms || reachabilityDecisionDag != this.ReachabilityDecisionDag || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(defaultLabel, this.DefaultLabel) || reportedNotExhaustive != this.ReportedNotExhaustive || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundConvertedSwitchExpression(this.Syntax, naturalTypeOpt, wasTargetTyped, expression, switchArms, decisionDag, defaultLabel, reportedNotExhaustive, type, this.HasErrors); + var result = new BoundConvertedSwitchExpression(this.Syntax, naturalTypeOpt, wasTargetTyped, expression, switchArms, reachabilityDecisionDag, defaultLabel, reportedNotExhaustive, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -7860,20 +7860,20 @@ public BoundStringInsert Update(BoundExpression value, BoundExpression? alignmen internal sealed partial class BoundIsPatternExpression : BoundExpression { - public BoundIsPatternExpression(SyntaxNode syntax, BoundExpression expression, BoundPattern pattern, bool isNegated, BoundDecisionDag decisionDag, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol? type, bool hasErrors = false) - : base(BoundKind.IsPatternExpression, syntax, type, hasErrors || expression.HasErrors() || pattern.HasErrors() || decisionDag.HasErrors()) + public BoundIsPatternExpression(SyntaxNode syntax, BoundExpression expression, BoundPattern pattern, bool isNegated, BoundDecisionDag reachabilityDecisionDag, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol? type, bool hasErrors = false) + : base(BoundKind.IsPatternExpression, syntax, type, hasErrors || expression.HasErrors() || pattern.HasErrors() || reachabilityDecisionDag.HasErrors()) { RoslynDebug.Assert(expression is object, "Field 'expression' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(pattern is object, "Field 'pattern' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); - RoslynDebug.Assert(decisionDag is object, "Field 'decisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(reachabilityDecisionDag is object, "Field 'reachabilityDecisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(whenTrueLabel is object, "Field 'whenTrueLabel' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(whenFalseLabel is object, "Field 'whenFalseLabel' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.Expression = expression; this.Pattern = pattern; this.IsNegated = isNegated; - this.DecisionDag = decisionDag; + this.ReachabilityDecisionDag = reachabilityDecisionDag; this.WhenTrueLabel = whenTrueLabel; this.WhenFalseLabel = whenFalseLabel; } @@ -7885,7 +7885,7 @@ public BoundIsPatternExpression(SyntaxNode syntax, BoundExpression expression, B public bool IsNegated { get; } - public BoundDecisionDag DecisionDag { get; } + public BoundDecisionDag ReachabilityDecisionDag { get; } public LabelSymbol WhenTrueLabel { get; } @@ -7893,11 +7893,11 @@ public BoundIsPatternExpression(SyntaxNode syntax, BoundExpression expression, B [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitIsPatternExpression(this); - public BoundIsPatternExpression Update(BoundExpression expression, BoundPattern pattern, bool isNegated, BoundDecisionDag decisionDag, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol? type) + public BoundIsPatternExpression Update(BoundExpression expression, BoundPattern pattern, bool isNegated, BoundDecisionDag reachabilityDecisionDag, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol? type) { - if (expression != this.Expression || pattern != this.Pattern || isNegated != this.IsNegated || decisionDag != this.DecisionDag || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(whenTrueLabel, this.WhenTrueLabel) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(whenFalseLabel, this.WhenFalseLabel) || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (expression != this.Expression || pattern != this.Pattern || isNegated != this.IsNegated || reachabilityDecisionDag != this.ReachabilityDecisionDag || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(whenTrueLabel, this.WhenTrueLabel) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(whenFalseLabel, this.WhenFalseLabel) || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundIsPatternExpression(this.Syntax, expression, pattern, isNegated, decisionDag, whenTrueLabel, whenFalseLabel, type, this.HasErrors); + var result = new BoundIsPatternExpression(this.Syntax, expression, pattern, isNegated, reachabilityDecisionDag, whenTrueLabel, whenFalseLabel, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -11146,9 +11146,9 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor { BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray switchSections = this.VisitList(node.SwitchSections); - BoundDecisionDag decisionDag = node.DecisionDag; + BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; BoundSwitchLabel? defaultLabel = (BoundSwitchLabel?)this.Visit(node.DefaultLabel); - return node.Update(expression, node.InnerLocals, node.InnerLocalFunctions, switchSections, decisionDag, defaultLabel, node.BreakLabel); + return node.Update(expression, node.InnerLocals, node.InnerLocalFunctions, switchSections, reachabilityDecisionDag, defaultLabel, node.BreakLabel); } public override BoundNode? VisitSwitchDispatch(BoundSwitchDispatch node) { @@ -11320,18 +11320,18 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor { BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray switchArms = this.VisitList(node.SwitchArms); - BoundDecisionDag decisionDag = node.DecisionDag; + BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; TypeSymbol? type = this.VisitType(node.Type); - return node.Update(expression, switchArms, decisionDag, node.DefaultLabel, node.ReportedNotExhaustive, type); + return node.Update(expression, switchArms, reachabilityDecisionDag, node.DefaultLabel, node.ReportedNotExhaustive, type); } public override BoundNode? VisitConvertedSwitchExpression(BoundConvertedSwitchExpression node) { BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray switchArms = this.VisitList(node.SwitchArms); - BoundDecisionDag decisionDag = node.DecisionDag; + BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; TypeSymbol? naturalTypeOpt = this.VisitType(node.NaturalTypeOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(naturalTypeOpt, node.WasTargetTyped, expression, switchArms, decisionDag, node.DefaultLabel, node.ReportedNotExhaustive, type); + return node.Update(naturalTypeOpt, node.WasTargetTyped, expression, switchArms, reachabilityDecisionDag, node.DefaultLabel, node.ReportedNotExhaustive, type); } public override BoundNode? VisitDecisionDag(BoundDecisionDag node) { @@ -11800,9 +11800,9 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor { BoundExpression expression = (BoundExpression)this.Visit(node.Expression); BoundPattern pattern = (BoundPattern)this.Visit(node.Pattern); - BoundDecisionDag decisionDag = node.DecisionDag; + BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; TypeSymbol? type = this.VisitType(node.Type); - return node.Update(expression, pattern, node.IsNegated, decisionDag, node.WhenTrueLabel, node.WhenFalseLabel, type); + return node.Update(expression, pattern, node.IsNegated, reachabilityDecisionDag, node.WhenTrueLabel, node.WhenFalseLabel, type); } public override BoundNode? VisitConstantPattern(BoundConstantPattern node) { @@ -13036,9 +13036,9 @@ public NullabilityRewriter(ImmutableDictionary innerLocalFunctions = GetUpdatedArray(node, node.InnerLocalFunctions); BoundExpression expression = (BoundExpression)this.Visit(node.Expression); ImmutableArray switchSections = this.VisitList(node.SwitchSections); - BoundDecisionDag decisionDag = node.DecisionDag; + BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; BoundSwitchLabel? defaultLabel = (BoundSwitchLabel?)this.Visit(node.DefaultLabel); - return node.Update(expression, innerLocals, innerLocalFunctions, switchSections, decisionDag, defaultLabel, node.BreakLabel); + return node.Update(expression, innerLocals, innerLocalFunctions, switchSections, reachabilityDecisionDag, defaultLabel, node.BreakLabel); } public override BoundNode? VisitSwitchDispatch(BoundSwitchDispatch node) @@ -13272,17 +13272,17 @@ public NullabilityRewriter(ImmutableDictionary switchArms = this.VisitList(node.SwitchArms); - BoundDecisionDag decisionDag = node.DecisionDag; + BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; BoundUnconvertedSwitchExpression updatedNode; if (_updatedNullabilities.TryGetValue(node, out (NullabilityInfo Info, TypeSymbol? Type) infoAndType)) { - updatedNode = node.Update(expression, switchArms, decisionDag, node.DefaultLabel, node.ReportedNotExhaustive, infoAndType.Type); + updatedNode = node.Update(expression, switchArms, reachabilityDecisionDag, node.DefaultLabel, node.ReportedNotExhaustive, infoAndType.Type); updatedNode.TopLevelNullability = infoAndType.Info; } else { - updatedNode = node.Update(expression, switchArms, decisionDag, node.DefaultLabel, node.ReportedNotExhaustive, node.Type); + updatedNode = node.Update(expression, switchArms, reachabilityDecisionDag, node.DefaultLabel, node.ReportedNotExhaustive, node.Type); } return updatedNode; } @@ -13292,17 +13292,17 @@ public NullabilityRewriter(ImmutableDictionary switchArms = this.VisitList(node.SwitchArms); - BoundDecisionDag decisionDag = node.DecisionDag; + BoundDecisionDag reachabilityDecisionDag = node.ReachabilityDecisionDag; BoundConvertedSwitchExpression updatedNode; if (_updatedNullabilities.TryGetValue(node, out (NullabilityInfo Info, TypeSymbol? Type) infoAndType)) { - updatedNode = node.Update(naturalTypeOpt, node.WasTargetTyped, expression, switchArms, decisionDag, node.DefaultLabel, node.ReportedNotExhaustive, infoAndType.Type!); + updatedNode = node.Update(naturalTypeOpt, node.WasTargetTyped, expression, switchArms, reachabilityDecisionDag, node.DefaultLabel, node.ReportedNotExhaustive, infoAndType.Type!); updatedNode.TopLevelNullability = infoAndType.Info; } else { - updatedNode = node.Update(naturalTypeOpt, node.WasTargetTyped, expression, switchArms, decisionDag, node.DefaultLabel, node.ReportedNotExhaustive, node.Type); + updatedNode = node.Update(naturalTypeOpt, node.WasTargetTyped, expression, switchArms, reachabilityDecisionDag, node.DefaultLabel, node.ReportedNotExhaustive, node.Type); } return updatedNode; } @@ -14259,17 +14259,17 @@ public NullabilityRewriter(ImmutableDictionaryThe first part of an interpolated string, $" or $@" + /// The first part of an interpolated string, $" or $@" or $""" public SyntaxToken StringStartToken => this.stringStartToken; /// List of parts of the interpolated string, each one is either a literal part or an interpolation. public Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Contents => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.contents); @@ -12225,10 +12225,14 @@ internal InterpolationSyntax(SyntaxKind kind, SyntaxToken openBraceToken, Expres this.closeBraceToken = closeBraceToken; } + /// This could be a single { or multiple in a row (in the case of an interpolation in a raw interpolated string). public SyntaxToken OpenBraceToken => this.openBraceToken; public ExpressionSyntax Expression => this.expression; public InterpolationAlignmentClauseSyntax? AlignmentClause => this.alignmentClause; public InterpolationFormatClauseSyntax? FormatClause => this.formatClause; + /// + /// This could be a single } or multiple in a row (in the case of an interpolation in a raw interpolated string). + /// public SyntaxToken CloseBraceToken => this.closeBraceToken; internal override GreenNode? GetSlot(int index) @@ -36284,6 +36288,8 @@ public LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxToken to case SyntaxKind.ArgListKeyword: case SyntaxKind.NumericLiteralToken: case SyntaxKind.StringLiteralToken: + case SyntaxKind.MultiLineRawStringLiteralToken: + case SyntaxKind.SingleLineRawStringLiteralToken: case SyntaxKind.CharacterLiteralToken: case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: @@ -37130,11 +37136,18 @@ public InterpolatedStringExpressionSyntax InterpolatedStringExpression(SyntaxTok switch (stringStartToken.Kind) { case SyntaxKind.InterpolatedStringStartToken: - case SyntaxKind.InterpolatedVerbatimStringStartToken: break; + case SyntaxKind.InterpolatedVerbatimStringStartToken: + case SyntaxKind.InterpolatedSingleLineRawStringStartToken: + case SyntaxKind.InterpolatedMultiLineRawStringStartToken: break; default: throw new ArgumentException(nameof(stringStartToken)); } if (stringEndToken == null) throw new ArgumentNullException(nameof(stringEndToken)); - if (stringEndToken.Kind != SyntaxKind.InterpolatedStringEndToken) throw new ArgumentException(nameof(stringEndToken)); + switch (stringEndToken.Kind) + { + case SyntaxKind.InterpolatedStringEndToken: + case SyntaxKind.InterpolatedRawStringEndToken: break; + default: throw new ArgumentException(nameof(stringEndToken)); + } #endif int hash; @@ -41298,6 +41311,8 @@ public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxT case SyntaxKind.ArgListKeyword: case SyntaxKind.NumericLiteralToken: case SyntaxKind.StringLiteralToken: + case SyntaxKind.MultiLineRawStringLiteralToken: + case SyntaxKind.SingleLineRawStringLiteralToken: case SyntaxKind.CharacterLiteralToken: case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: @@ -42144,11 +42159,18 @@ public static InterpolatedStringExpressionSyntax InterpolatedStringExpression(Sy switch (stringStartToken.Kind) { case SyntaxKind.InterpolatedStringStartToken: - case SyntaxKind.InterpolatedVerbatimStringStartToken: break; + case SyntaxKind.InterpolatedVerbatimStringStartToken: + case SyntaxKind.InterpolatedSingleLineRawStringStartToken: + case SyntaxKind.InterpolatedMultiLineRawStringStartToken: break; default: throw new ArgumentException(nameof(stringStartToken)); } if (stringEndToken == null) throw new ArgumentNullException(nameof(stringEndToken)); - if (stringEndToken.Kind != SyntaxKind.InterpolatedStringEndToken) throw new ArgumentException(nameof(stringEndToken)); + switch (stringEndToken.Kind) + { + case SyntaxKind.InterpolatedStringEndToken: + case SyntaxKind.InterpolatedRawStringEndToken: break; + default: throw new ArgumentException(nameof(stringEndToken)); + } #endif int hash; diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs index ce862c9412c74..049bb9a4f6a90 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs @@ -2848,6 +2848,8 @@ public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxT case SyntaxKind.ArgListKeyword: case SyntaxKind.NumericLiteralToken: case SyntaxKind.StringLiteralToken: + case SyntaxKind.MultiLineRawStringLiteralToken: + case SyntaxKind.SingleLineRawStringLiteralToken: case SyntaxKind.CharacterLiteralToken: case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: @@ -2858,24 +2860,6 @@ public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxT return (LiteralExpressionSyntax)Syntax.InternalSyntax.SyntaxFactory.LiteralExpression(kind, (Syntax.InternalSyntax.SyntaxToken)token.Node!).CreateRed(); } - /// Creates a new LiteralExpressionSyntax instance. - public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind) - => SyntaxFactory.LiteralExpression(kind, SyntaxFactory.Token(GetLiteralExpressionTokenKind(kind))); - - private static SyntaxKind GetLiteralExpressionTokenKind(SyntaxKind kind) - => kind switch - { - SyntaxKind.ArgListExpression => SyntaxKind.ArgListKeyword, - SyntaxKind.NumericLiteralExpression => SyntaxKind.NumericLiteralToken, - SyntaxKind.StringLiteralExpression => SyntaxKind.StringLiteralToken, - SyntaxKind.CharacterLiteralExpression => SyntaxKind.CharacterLiteralToken, - SyntaxKind.TrueLiteralExpression => SyntaxKind.TrueKeyword, - SyntaxKind.FalseLiteralExpression => SyntaxKind.FalseKeyword, - SyntaxKind.NullLiteralExpression => SyntaxKind.NullKeyword, - SyntaxKind.DefaultLiteralExpression => SyntaxKind.DefaultKeyword, - _ => throw new ArgumentOutOfRangeException(), - }; - /// Creates a new MakeRefExpressionSyntax instance. public static MakeRefExpressionSyntax MakeRefExpression(SyntaxToken keyword, SyntaxToken openParenToken, ExpressionSyntax expression, SyntaxToken closeParenToken) { @@ -3522,20 +3506,23 @@ public static InterpolatedStringExpressionSyntax InterpolatedStringExpression(Sy switch (stringStartToken.Kind()) { case SyntaxKind.InterpolatedStringStartToken: - case SyntaxKind.InterpolatedVerbatimStringStartToken: break; + case SyntaxKind.InterpolatedVerbatimStringStartToken: + case SyntaxKind.InterpolatedSingleLineRawStringStartToken: + case SyntaxKind.InterpolatedMultiLineRawStringStartToken: break; default: throw new ArgumentException(nameof(stringStartToken)); } - if (stringEndToken.Kind() != SyntaxKind.InterpolatedStringEndToken) throw new ArgumentException(nameof(stringEndToken)); + switch (stringEndToken.Kind()) + { + case SyntaxKind.InterpolatedStringEndToken: + case SyntaxKind.InterpolatedRawStringEndToken: break; + default: throw new ArgumentException(nameof(stringEndToken)); + } return (InterpolatedStringExpressionSyntax)Syntax.InternalSyntax.SyntaxFactory.InterpolatedStringExpression((Syntax.InternalSyntax.SyntaxToken)stringStartToken.Node!, contents.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken)stringEndToken.Node!).CreateRed(); } /// Creates a new InterpolatedStringExpressionSyntax instance. - public static InterpolatedStringExpressionSyntax InterpolatedStringExpression(SyntaxToken stringStartToken, SyntaxList contents) - => SyntaxFactory.InterpolatedStringExpression(stringStartToken, contents, SyntaxFactory.Token(SyntaxKind.InterpolatedStringEndToken)); - - /// Creates a new InterpolatedStringExpressionSyntax instance. - public static InterpolatedStringExpressionSyntax InterpolatedStringExpression(SyntaxToken stringStartToken) - => SyntaxFactory.InterpolatedStringExpression(stringStartToken, default, SyntaxFactory.Token(SyntaxKind.InterpolatedStringEndToken)); + public static InterpolatedStringExpressionSyntax InterpolatedStringExpression(SyntaxToken stringStartToken, SyntaxToken stringEndToken) + => SyntaxFactory.InterpolatedStringExpression(stringStartToken, default, stringEndToken); /// Creates a new IsPatternExpressionSyntax instance. public static IsPatternExpressionSyntax IsPatternExpression(ExpressionSyntax expression, SyntaxToken isKeyword, PatternSyntax pattern) diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs index a3893c47708be..da5214e1246b6 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs @@ -4774,7 +4774,7 @@ internal InterpolatedStringExpressionSyntax(InternalSyntax.CSharpSyntaxNode gree { } - /// The first part of an interpolated string, $" or $@" + /// The first part of an interpolated string, $" or $@" or $""" public SyntaxToken StringStartToken => new SyntaxToken(this, ((Syntax.InternalSyntax.InterpolatedStringExpressionSyntax)this.Green).stringStartToken, Position, 0); /// List of parts of the interpolated string, each one is either a literal part or an interpolation. @@ -5783,6 +5783,7 @@ internal InterpolationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? { } + /// This could be a single { or multiple in a row (in the case of an interpolation in a raw interpolated string). public SyntaxToken OpenBraceToken => new SyntaxToken(this, ((Syntax.InternalSyntax.InterpolationSyntax)this.Green).openBraceToken, Position, 0); public ExpressionSyntax Expression => GetRed(ref this.expression, 1)!; @@ -5791,6 +5792,9 @@ internal InterpolationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? public InterpolationFormatClauseSyntax? FormatClause => GetRed(ref this.formatClause, 3); + /// + /// This could be a single } or multiple in a row (in the case of an interpolation in a raw interpolated string). + /// public SyntaxToken CloseBraceToken => new SyntaxToken(this, ((Syntax.InternalSyntax.InterpolationSyntax)this.Green).closeBraceToken, GetChildPosition(4), GetChildIndex(4)); internal override SyntaxNode? GetNodeSlot(int index) diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs index 97db1670c6348..704f12678935d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs @@ -75,6 +75,7 @@ protected override BoundStatement GenerateSetResultCall() // ... this.state = FinishedState; ... // if (this.combinedTokens != null) { this.combinedTokens.Dispose(); this.combinedTokens = null; } // for enumerables only + // _current = default; // this.builder.Complete(); // this.promiseOfValueOrEnd.SetResult(false); // return; @@ -90,6 +91,8 @@ protected override BoundStatement GenerateSetResultCall() AddDisposeCombinedTokensIfNeeded(builder); builder.AddRange( + // _current = default; + GenerateClearCurrent(), GenerateCompleteOnBuilder(), // this.promiseOfValueOrEnd.SetResult(false); generateSetResultOnPromise(false), @@ -109,6 +112,13 @@ BoundExpressionStatement generateSetResultOnPromise(bool result) } } + private BoundExpressionStatement GenerateClearCurrent() + { + // _current = default; + var currentField = _asyncIteratorInfo.CurrentField; + return F.Assignment(F.InstanceField(currentField), F.Default(currentField.Type)); + } + private BoundExpressionStatement GenerateCompleteOnBuilder() { // Produce: @@ -143,6 +153,9 @@ protected override BoundStatement GenerateSetExceptionCall(LocalSymbol exception // if (this.combinedTokens != null) { this.combinedTokens.Dispose(); this.combinedTokens = null; } // for enumerables only AddDisposeCombinedTokensIfNeeded(builder); + // _current = default; + builder.Add(GenerateClearCurrent()); + // this.builder.Complete(); builder.Add(GenerateCompleteOnBuilder()); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheContainer.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheContainer.cs new file mode 100644 index 0000000000000..21d49a0ec2fdc --- /dev/null +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheContainer.cs @@ -0,0 +1,99 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols; + +/// +/// This type is synthesized to hold the cached delegates that target static method groups. +/// +internal sealed class DelegateCacheContainer : SynthesizedContainer +{ + private readonly Symbol _containingSymbol; + private readonly NamedTypeSymbol? _constructedContainer; + private readonly Dictionary<(TypeSymbol, MethodSymbol), FieldSymbol> _delegateFields = new(CLRSignatureComparer.Instance); + + /// Creates a type-scope concrete delegate cache container. + internal DelegateCacheContainer(TypeSymbol containingType, int generationOrdinal) + : base(GeneratedNames.DelegateCacheContainerType(generationOrdinal), containingMethod: null) + { + Debug.Assert(containingType.IsDefinition); + + _containingSymbol = containingType; + } + + /// Creates a method-scope generic delegate cache container. + internal DelegateCacheContainer(MethodSymbol ownerMethod, int topLevelMethodOrdinal, int ownerUniqueId, int generationOrdinal) + : base(GeneratedNames.DelegateCacheContainerType(generationOrdinal, ownerMethod.Name, topLevelMethodOrdinal, ownerUniqueId), ownerMethod) + { + Debug.Assert(ownerMethod.IsDefinition); + Debug.Assert(ownerMethod.Arity > 0); + + _containingSymbol = ownerMethod.ContainingType; + _constructedContainer = Construct(ConstructedFromTypeParameters); + } + + public override Symbol ContainingSymbol => _containingSymbol; + + public override bool AreLocalsZeroed => throw ExceptionUtilities.Unreachable; + + public override TypeKind TypeKind => TypeKind.Class; + + public override bool IsStatic => true; + + internal override bool IsRecord => false; + + internal override bool IsRecordStruct => false; + + internal override bool HasPossibleWellKnownCloneMethod() => false; + + internal FieldSymbol GetOrAddCacheField(SyntheticBoundNodeFactory factory, TypeSymbol delegateType, MethodSymbol targetMethod) + { + Debug.Assert(delegateType.IsDelegateType()); + + if (_delegateFields.TryGetValue((delegateType, targetMethod), out var field)) + { + return field; + } + + var fieldType = TypeParameters.IsEmpty ? delegateType : TypeMap.SubstituteType(delegateType).Type; + var fieldName = GeneratedNames.DelegateCacheContainerFieldName(_delegateFields.Count, targetMethod.Name); + + field = new SynthesizedFieldSymbol(this, fieldType, fieldName, isPublic: true, isStatic: true); + factory.AddField(this, field); + + if (!TypeParameters.IsEmpty) + { + Debug.Assert(_constructedContainer is { }); + + field = field.AsMember(_constructedContainer); + } + + _delegateFields.Add((delegateType, targetMethod), field); + + return field; + } + + private sealed class CLRSignatureComparer : IEqualityComparer<(TypeSymbol delegateType, MethodSymbol targetMethod)> + { + public static readonly CLRSignatureComparer Instance = new(); + + public bool Equals((TypeSymbol delegateType, MethodSymbol targetMethod) x, (TypeSymbol delegateType, MethodSymbol targetMethod) y) + { + var symbolComparer = SymbolEqualityComparer.CLRSignature; + + return symbolComparer.Equals(x.delegateType, y.delegateType) && symbolComparer.Equals(x.targetMethod, y.targetMethod); + } + + public int GetHashCode((TypeSymbol delegateType, MethodSymbol targetMethod) conversion) + { + var symbolComparer = SymbolEqualityComparer.CLRSignature; + + return Hash.Combine(symbolComparer.GetHashCode(conversion.delegateType), symbolComparer.GetHashCode(conversion.targetMethod)); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheRewriter.cs new file mode 100644 index 0000000000000..a4c8eb97dad58 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/DelegateCacheRewriter.cs @@ -0,0 +1,221 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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 Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp; + +/// +/// This type helps rewrite the delegate creations that target static method groups to use a cached instance of delegate. +/// +internal sealed class DelegateCacheRewriter +{ + private readonly SyntheticBoundNodeFactory _factory; + private readonly int _topLevelMethodOrdinal; + + private Dictionary? _genericCacheContainers; + + internal DelegateCacheRewriter(SyntheticBoundNodeFactory factory, int topLevelMethodOrdinal) + { + Debug.Assert(factory.TopLevelMethod is { }); + + _factory = factory; + _topLevelMethodOrdinal = topLevelMethodOrdinal; + } + + internal static bool CanRewrite(BoundDelegateCreationExpression boundDelegateCreation) + { + var targetMethod = boundDelegateCreation.MethodOpt; + + Debug.Assert(targetMethod is { }); + + return targetMethod.IsStatic && !boundDelegateCreation.IsExtensionMethod; + } + + internal BoundExpression Rewrite(BoundDelegateCreationExpression boundDelegateCreation) + { + var targetMethod = boundDelegateCreation.MethodOpt; + var delegateType = boundDelegateCreation.Type; + + Debug.Assert(targetMethod is { }); + + var oldSyntax = _factory.Syntax; + _factory.Syntax = boundDelegateCreation.Syntax; + + var cacheContainer = GetOrAddCacheContainer(delegateType, targetMethod); + var cacheField = cacheContainer.GetOrAddCacheField(_factory, delegateType, targetMethod); + + var boundCacheField = _factory.Field(receiver: null, cacheField); + var rewrittenNode = _factory.Coalesce(boundCacheField, _factory.AssignmentExpression(boundCacheField, boundDelegateCreation)); + + _factory.Syntax = oldSyntax; + + return rewrittenNode; + } + + private DelegateCacheContainer GetOrAddCacheContainer(TypeSymbol delegateType, MethodSymbol targetMethod) + { + Debug.Assert(_factory.ModuleBuilderOpt is { }); + Debug.Assert(_factory.CurrentFunction is { }); + + var generation = _factory.ModuleBuilderOpt.CurrentGenerationOrdinal; + + DelegateCacheContainer? container; + + // We don't need to synthesize a container for each and every function. + // + // For example: + // void LF1() + // { + // void LF2() + // { + // void LF3() + // { + // Func d = SomeMethod; + // static void LF4 () { Func d = SomeMethod; } + // } + // + // void LF5() + // { + // Func d = SomeMethod; + // } + // } + // } + // + // In the above case, only one cached delegate is necessary, and it could be assigned to the container 'owned' by LF1. + + if (!TryGetOwnerFunction(_factory.CurrentFunction, delegateType, targetMethod, out var ownerFunction)) + { + var typeCompilationState = _factory.CompilationState; + container = typeCompilationState.ConcreteDelegateCacheContainer; + + if (container is { }) + { + return container; + } + + container = new DelegateCacheContainer(typeCompilationState.Type, generation); + typeCompilationState.ConcreteDelegateCacheContainer = container; + } + else + { + var containers = _genericCacheContainers ??= new Dictionary(ReferenceEqualityComparer.Instance); + + if (containers.TryGetValue(ownerFunction, out container)) + { + return container; + } + + container = new DelegateCacheContainer(ownerFunction, _topLevelMethodOrdinal, containers.Count, generation); + containers.Add(ownerFunction, container); + } + + _factory.AddNestedType(container); + + return container; + } + + private static bool TryGetOwnerFunction(MethodSymbol currentFunction, TypeSymbol delegateType, MethodSymbol targetMethod, [NotNullWhen(true)] out MethodSymbol? ownerFunction) + { + if (targetMethod.MethodKind == MethodKind.LocalFunction) + { + // Local functions can use type parameters from their enclosing methods! + // + // For example: + // void Test() + // { + // var t = Target; + // static object Target() => default(T); + // } + // + // Therefore, without too much analysis, we select the closest generic enclosing function as the cache container owner. + + for (Symbol? enclosingSymbol = currentFunction; enclosingSymbol is MethodSymbol enclosingMethod; enclosingSymbol = enclosingSymbol.ContainingSymbol) + { + if (enclosingMethod.Arity > 0) + { + ownerFunction = enclosingMethod; + return true; + } + } + + ownerFunction = null; + return false; + } + + // @AlekseyTs: It is Ok to create delegates for other method kinds as well. + // @jcouv: We'd likely want to pay attention to this code if this happens. + // What we really cared above was, + // - "Are there any type parameters from the target method that we cannot discover simply from it's signature?" + // As of C# 10, we only observe local functions could potentially answer yes, so we used that. + // If this is hit, feel free to change but please also add tests. + Debug.Assert(targetMethod.MethodKind == MethodKind.Ordinary); + + var usedTypeParameters = PooledHashSet.GetInstance(); + try + { + FindTypeParameters(delegateType, usedTypeParameters); + FindTypeParameters(targetMethod, usedTypeParameters); + + for (Symbol? enclosingSymbol = currentFunction; enclosingSymbol is MethodSymbol enclosingMethod; enclosingSymbol = enclosingSymbol.ContainingSymbol) + { + if (usedTypeParametersContains(usedTypeParameters, enclosingMethod.TypeParameters)) + { + ownerFunction = enclosingMethod; + return true; + } + } + + ownerFunction = null; + return false; + } + finally + { + usedTypeParameters.Free(); + } + + static bool usedTypeParametersContains(HashSet used, ImmutableArray typeParameters) + { + foreach (var typeParameter in typeParameters) + { + if (used.Contains(typeParameter)) + { + return true; + } + } + + return false; + } + } + + private static void FindTypeParameters(TypeSymbol type, HashSet result) + => type.VisitType(s_typeParameterSymbolCollector, result, visitCustomModifiers: true); + + private static void FindTypeParameters(MethodSymbol method, HashSet result) + { + FindTypeParameters(method.ContainingType, result); + + foreach (var typeArgument in method.TypeArgumentsWithAnnotations) + { + typeArgument.VisitType(type: null, typeWithAnnotationsPredicate: null, s_typeParameterSymbolCollector, result, visitCustomModifiers: true); + } + } + + private static readonly Func, bool, bool> s_typeParameterSymbolCollector = (typeSymbol, result, _) => + { + if (typeSymbol is TypeParameterSymbol typeParameter) + { + result.Add(typeParameter); + } + + return false; + }; +} diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.DecisionDagRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.DecisionDagRewriter.cs index 636c27dd9a20e..dac73e21a192b 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.DecisionDagRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.DecisionDagRewriter.cs @@ -1106,19 +1106,15 @@ private void LowerDecisionDagNode(BoundDecisionDagNode node, BoundDecisionDagNod { case BoundEvaluationDecisionDagNode evaluationNode: { - var e = evaluationNode.Evaluation; - if (e is not BoundDagAssignmentEvaluation) - { - BoundExpression sideEffect = LowerEvaluation(e); - Debug.Assert(sideEffect != null); - _loweredDecisionDag.Add(_factory.ExpressionStatement(sideEffect)); - - // We add a hidden sequence point after the evaluation's side-effect, which may be a call out - // to user code such as `Deconstruct` or a property get, to permit edit-and-continue to - // synchronize on changes. - if (GenerateInstrumentation) - _loweredDecisionDag.Add(_factory.HiddenSequencePoint()); - } + BoundExpression sideEffect = LowerEvaluation(evaluationNode.Evaluation); + Debug.Assert(sideEffect != null); + _loweredDecisionDag.Add(_factory.ExpressionStatement(sideEffect)); + + // We add a hidden sequence point after the evaluation's side-effect, which may be a call out + // to user code such as `Deconstruct` or a property get, to permit edit-and-continue to + // synchronize on changes. + if (GenerateInstrumentation) + _loweredDecisionDag.Add(_factory.HiddenSequencePoint()); if (nextNode != evaluationNode.Next) { diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs index f3ff587c91056..f7ab233390c9d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.PatternLocalRewriter.cs @@ -296,6 +296,7 @@ void addArg(RefKind refKind, BoundExpression expression) return _factory.AssignmentExpression(output, access); } + case BoundDagAssignmentEvaluation: default: throw ExceptionUtilities.UnexpectedValue(evaluation); } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs index c8c175ea65d0d..f4e50554a1d85 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs @@ -27,6 +27,8 @@ internal sealed partial class LocalRewriter : BoundTreeRewriterWithStackGuard private LoweredDynamicOperationFactory _dynamicFactory; private bool _sawLambdas; private int _availableLocalFunctionOrdinal; + private readonly int _topLevelMethodOrdinal; + private DelegateCacheRewriter? _lazyDelegateCacheRewriter; private bool _inExpressionLambda; private bool _sawAwait; @@ -57,6 +59,7 @@ private LocalRewriter( _dynamicFactory = new LoweredDynamicOperationFactory(factory, containingMethodOrdinal); _previousSubmissionFields = previousSubmissionFields; _allowOmissionOfConditionalCalls = allowOmissionOfConditionalCalls; + _topLevelMethodOrdinal = containingMethodOrdinal; _diagnostics = diagnostics; Debug.Assert(instrumenter != null); @@ -260,12 +263,7 @@ public override BoundNode VisitLambda(BoundLambda node) _instrumenter = RemoveDynamicAnalysisInjectors(oldInstrumenter); } - var visited = (BoundLambda)base.VisitLambda(node)!; - if (RewriteNullChecking(visited.Body) is BoundBlock newBody) - { - visited = visited.Update(visited.UnboundLambda, visited.Symbol, newBody, visited.Diagnostics, visited.Binder, visited.Type); - } - return visited; + return base.VisitLambda(node)!; } finally { @@ -330,13 +328,7 @@ static bool hasReturnTypeOrParameter(LocalFunctionSymbol localFunction, Func= MessageID.IDS_FeatureCacheStaticMethodGroupConversion.RequiredVersion() + && !_inExpressionLambda // The tree structure / meaning for expression trees should remain untouched. + && _factory.TopLevelMethod.MethodKind != MethodKind.StaticConstructor // Avoid caching twice if people do it manually. + && DelegateCacheRewriter.CanRewrite(boundDelegateCreation)) + { + var rewriter = _lazyDelegateCacheRewriter ??= new DelegateCacheRewriter(_factory, _topLevelMethodOrdinal); + return rewriter.Rewrite(boundDelegateCreation); + } + else + { + return boundDelegateCreation; + } } + default: break; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs index 5cfd96bb6a4c5..3ea8a02242513 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs @@ -14,30 +14,30 @@ internal sealed partial class LocalRewriter { public override BoundNode VisitIsPatternExpression(BoundIsPatternExpression node) { + BoundDecisionDag decisionDag = node.GetDecisionDagForLowering(_factory.Compilation); bool negated = node.IsNegated; BoundExpression result; - - if (canProduceLinearSequence(node.DecisionDag.RootNode, whenTrueLabel: node.WhenTrueLabel, whenFalseLabel: node.WhenFalseLabel)) + if (canProduceLinearSequence(decisionDag.RootNode, whenTrueLabel: node.WhenTrueLabel, whenFalseLabel: node.WhenFalseLabel)) { // If we can build a linear test sequence `(e1 && e2 && e3)` for the dag, do so. var isPatternRewriter = new IsPatternExpressionLinearLocalRewriter(node, this); - result = isPatternRewriter.LowerIsPatternAsLinearTestSequence(node, whenTrueLabel: node.WhenTrueLabel, whenFalseLabel: node.WhenFalseLabel); + result = isPatternRewriter.LowerIsPatternAsLinearTestSequence(node, decisionDag, whenTrueLabel: node.WhenTrueLabel, whenFalseLabel: node.WhenFalseLabel); isPatternRewriter.Free(); } - else if (canProduceLinearSequence(node.DecisionDag.RootNode, whenTrueLabel: node.WhenFalseLabel, whenFalseLabel: node.WhenTrueLabel)) + else if (canProduceLinearSequence(decisionDag.RootNode, whenTrueLabel: node.WhenFalseLabel, whenFalseLabel: node.WhenTrueLabel)) { // If we can build a linear test sequence with the whenTrue and whenFalse labels swapped, then negate the // result. This would typically arise when the source contains `e is not pattern`. negated = !negated; var isPatternRewriter = new IsPatternExpressionLinearLocalRewriter(node, this); - result = isPatternRewriter.LowerIsPatternAsLinearTestSequence(node, whenTrueLabel: node.WhenFalseLabel, whenFalseLabel: node.WhenTrueLabel); + result = isPatternRewriter.LowerIsPatternAsLinearTestSequence(node, decisionDag, whenTrueLabel: node.WhenFalseLabel, whenFalseLabel: node.WhenTrueLabel); isPatternRewriter.Free(); } else { // We need to lower a generalized dag, so we produce a label for the true and false branches and assign to a temporary containing the result. var isPatternRewriter = new IsPatternExpressionGeneralLocalRewriter(node.Syntax, this); - result = isPatternRewriter.LowerGeneralIsPattern(node); + result = isPatternRewriter.LowerGeneralIsPattern(node, decisionDag); isPatternRewriter.Free(); } @@ -104,13 +104,12 @@ public IsPatternExpressionGeneralLocalRewriter( _statements.Free(); } - internal BoundExpression LowerGeneralIsPattern(BoundIsPatternExpression node) + internal BoundExpression LowerGeneralIsPattern(BoundIsPatternExpression node, BoundDecisionDag decisionDag) { _factory.Syntax = node.Syntax; var resultBuilder = ArrayBuilder.GetInstance(); var inputExpression = _localRewriter.VisitExpression(node.Expression); - BoundDecisionDag decisionDag = ShareTempsIfPossibleAndEvaluateInput( - node.DecisionDag, inputExpression, resultBuilder, out _); + decisionDag = ShareTempsIfPossibleAndEvaluateInput(decisionDag, inputExpression, resultBuilder, out _); // lower the decision dag. ImmutableArray loweredDag = LowerDecisionDagCore(decisionDag); @@ -192,8 +191,6 @@ private void LowerOneTest(BoundDagTest test, bool invert = false) _factory.Syntax = test.Syntax; switch (test) { - case BoundDagAssignmentEvaluation: - return; case BoundDagEvaluation eval: { var sideEffect = LowerEvaluation(eval); @@ -217,9 +214,11 @@ private void LowerOneTest(BoundDagTest test, bool invert = false) } public BoundExpression LowerIsPatternAsLinearTestSequence( - BoundIsPatternExpression isPatternExpression, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel) + BoundIsPatternExpression isPatternExpression, + BoundDecisionDag decisionDag, + LabelSymbol whenTrueLabel, + LabelSymbol whenFalseLabel) { - BoundDecisionDag decisionDag = isPatternExpression.DecisionDag; BoundExpression loweredInput = _localRewriter.VisitExpression(isPatternExpression.Expression); // The optimization of sharing pattern-matching temps with user variables can always apply to diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullChecking.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullChecking.cs index 406e106f62ad5..3010abf5a7816 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullChecking.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullChecking.cs @@ -11,25 +11,9 @@ namespace Microsoft.CodeAnalysis.CSharp { internal sealed partial class LocalRewriter { - private BoundBlock? RewriteNullChecking(BoundBlock? block) - { - if (block is null) - { - return null; - } - - Debug.Assert(_factory.CurrentFunction is not null); - var statementList = TryConstructNullCheckedStatementList(_factory.CurrentFunction.Parameters, block.Statements, _factory); - if (statementList.IsDefault) - { - return null; - } - return _factory.Block(block.Locals, statementList); - } - - internal static ImmutableArray TryConstructNullCheckedStatementList(ImmutableArray parameters, - ImmutableArray existingStatements, - SyntheticBoundNodeFactory factory) + internal static ImmutableArray ConstructNullCheckedStatementList( + ImmutableArray parameters, + SyntheticBoundNodeFactory factory) { ArrayBuilder? statementList = null; MethodSymbol? throwIfNullMethod = null; @@ -46,13 +30,8 @@ internal static ImmutableArray TryConstructNullCheckedStatementL statementList.Add(constructedIf); } } - if (statementList is null) - { - return default; - } - statementList.AddRange(existingStatements); - return statementList.ToImmutableAndFree(); + return statementList?.ToImmutableAndFree() ?? ImmutableArray.Empty; } private static BoundStatement ConstructNullCheckHelperCall(ParameterSymbol parameter, ref MethodSymbol? throwIfNullMethod, SyntheticBoundNodeFactory factory) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs index e82caceede5d8..cd187029d23b0 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; +using System.Diagnostics; namespace Microsoft.CodeAnalysis.CSharp { @@ -94,7 +95,9 @@ private BoundStatement LowerSwitchStatement(BoundSwitchStatement node) outerVariables.AddRange(node.InnerLocals); // Evaluate the input and set up sharing for dag temps with user variables - BoundDecisionDag decisionDag = ShareTempsIfPossibleAndEvaluateInput(node.DecisionDag, loweredSwitchGoverningExpression, result, out _); + BoundDecisionDag decisionDag = ShareTempsIfPossibleAndEvaluateInput( + node.GetDecisionDagForLowering(_factory.Compilation), + loweredSwitchGoverningExpression, result, out _); // In a switch statement, there is a hidden sequence point after evaluating the input at the start of // the code to handle the decision dag. This is necessary so that jumps back from a `when` clause into diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_SwitchExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_SwitchExpression.cs index 9214a7b639b0b..7b3df3ff93ff4 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_SwitchExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_SwitchExpression.cs @@ -49,8 +49,11 @@ private BoundExpression LowerSwitchExpression(BoundConvertedSwitchExpression nod var result = ArrayBuilder.GetInstance(); var outerVariables = ArrayBuilder.GetInstance(); var loweredSwitchGoverningExpression = _localRewriter.VisitExpression(node.Expression); + BoundDecisionDag decisionDag = ShareTempsIfPossibleAndEvaluateInput( - node.DecisionDag, loweredSwitchGoverningExpression, result, out BoundExpression savedInputExpression); + node.GetDecisionDagForLowering(_factory.Compilation, out LabelSymbol? defaultLabel), + loweredSwitchGoverningExpression, result, out BoundExpression savedInputExpression); + Debug.Assert(savedInputExpression != null); object restorePointForEnclosingStatement = new object(); @@ -115,9 +118,9 @@ private BoundExpression LowerSwitchExpression(BoundConvertedSwitchExpression nod } _factory.Syntax = node.Syntax; - if (node.DefaultLabel != null) + if (defaultLabel is not null) { - result.Add(_factory.Label(node.DefaultLabel)); + result.Add(_factory.Label(defaultLabel)); if (produceDetailedSequencePoints) result.Add(new BoundRestorePreviousSequencePoint(node.Syntax, restorePointForSwitchBody)); var objectType = _factory.SpecialType(SpecialType.System_Object); diff --git a/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs b/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs index c235cf371059b..86f9fc49a6cf3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs @@ -311,11 +311,26 @@ private BoundExpression Spill( continue; case BoundKind.Sequence: - // neither the side-effects nor the value of the sequence contains await - // (otherwise it would be converted to a SpillSequenceBuilder). if (refKind != RefKind.None) { - return expression; + var sequence = (BoundSequence)expression; + + PromoteAndAddLocals(builder, sequence.Locals); + builder.AddExpressions(sequence.SideEffects); + expression = sequence.Value; + continue; + } + + goto default; + + case BoundKind.AssignmentOperator: + var assignment = (BoundAssignmentOperator)expression; + if (assignment.IsRef && + assignment is not { Left.Kind: BoundKind.Local, Right.Kind: BoundKind.ArrayAccess }) // Optimize for some known to be safe scenarios. + { + var left = Spill(builder, assignment.Left, RefKind.Ref); + var right = Spill(builder, assignment.Right, RefKind.Ref); + expression = assignment.Update(left, right, assignment.IsRef, assignment.Type); } goto default; diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs index df7008cb75f7e..0616f66995d3a 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs @@ -320,8 +320,7 @@ protected BoundStatement GenerateParameterStorage(LocalSymbol stateMachineVariab } var builtBody = bodyBuilder.ToImmutableAndFree(); - ImmutableArray newBody = LocalRewriter.TryConstructNullCheckedStatementList(method.Parameters, builtBody, F); - return newBody.IsDefault ? F.Block(builtBody) : F.Block(ImmutableArray.Create(stateMachineVariable), newBody); + return F.Block(builtBody); } protected SynthesizedImplementationMethod OpenMethodImplementation( diff --git a/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj b/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj index fa18c2461beaa..b31469d28a312 100644 --- a/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj +++ b/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj @@ -6,7 +6,6 @@ Microsoft.CodeAnalysis.CSharp true netcoreapp3.1;netstandard2.0 - ..\CSharpCodeAnalysisRules.ruleset true full @@ -40,9 +39,6 @@ - - Designer - diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 7bea98e33b01f..5aaafb8b8e2c9 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -4391,6 +4391,8 @@ private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter) return true; } +#nullable enable + private ParameterSyntax ParseParameter() { if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameter(this.CurrentNode as CSharp.Syntax.ParameterSyntax)) @@ -4429,9 +4431,9 @@ private ParameterSyntax ParseParameter() // If we didn't already consume an equals sign as part of !!=, then try to scan one out now. equalsToken ??= TryEatToken(SyntaxKind.EqualsToken); - EqualsValueClauseSyntax equalsValueClause = null; - if (equalsToken != null) - equalsValueClause = CheckFeatureAvailability(_syntaxFactory.EqualsValueClause(equalsToken, this.ParseExpressionCore()), MessageID.IDS_FeatureOptionalParameter); + var equalsValueClause = equalsToken == null + ? null + : CheckFeatureAvailability(_syntaxFactory.EqualsValueClause(equalsToken, this.ParseExpressionCore()), MessageID.IDS_FeatureOptionalParameter); return _syntaxFactory.Parameter(attributes, modifiers.ToList(), type, identifier, exclamationExclamationToken, equalsValueClause); } @@ -4441,8 +4443,6 @@ private ParameterSyntax ParseParameter() } } -#nullable enable - /// /// Parses the !! following a parameter type and identifier. If the token /// is followed by !!= or ! !=, then the final equals will be returned through // (a { + // (a !! or (a !!= + // (a = // // In all other cases, parse out a type. var peek1 = this.PeekToken(1); @@ -13175,7 +13209,8 @@ private bool ShouldParseLambdaParameterType(bool hasModifier) peek1.Kind != SyntaxKind.CloseParenToken && peek1.Kind != SyntaxKind.EqualsGreaterThanToken && peek1.Kind != SyntaxKind.OpenBraceToken && - peek1.Kind != SyntaxKind.ExclamationToken) + peek1.Kind != SyntaxKind.ExclamationToken && + peek1.Kind != SyntaxKind.EqualsToken) { return true; } diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser_InterpolatedString.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser_InterpolatedString.cs index 4d16b3464faa1..137ff39d32cb0 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser_InterpolatedString.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser_InterpolatedString.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax { @@ -39,98 +41,277 @@ private ExpressionSyntax ParseInterpolatedStringToken() var originalToken = this.EatToken(); var originalText = originalToken.ValueText; // this is actually the source text + var originalTextSpan = originalText.AsSpan(); Debug.Assert(originalText[0] == '$' || originalText[0] == '@'); // compute the positions of the interpolations in the original string literal, if there was an error or not, - // and where the close quote can be found. + // and where the open and close quotes can be found. var interpolations = ArrayBuilder.GetInstance(); rescanInterpolation(out var kind, out var error, out var openQuoteRange, interpolations, out var closeQuoteRange); - var result = SyntaxFactory.InterpolatedStringExpression( - getOpenQuote(openQuoteRange), getContent(interpolations), getCloseQuote(closeQuoteRange)); + // Only bother trying to do dedentation if we have a multiline literal without errors. There's no point + // trying in the presence of errors as we may not even be able to determine what the dedentation should be. + var needsDedentation = kind == Lexer.InterpolatedStringKind.MultiLineRaw && error == null; + + var result = SyntaxFactory.InterpolatedStringExpression(getOpenQuote(), getContent(originalTextSpan), getCloseQuote()); interpolations.Free(); if (error != null) { - result = result.WithDiagnosticsGreen(new[] { error }); + // Errors are positioned relative to the start of the token that was lexed. Specifically relative to + // the starting `$` or `@`. However, when placed on a node like this, it will be relative to the node's + // full start. So we have to adjust the diagnostics taking that into account. + result = result.WithDiagnosticsGreen(MoveDiagnostics(new[] { error }, originalToken.GetLeadingTrivia()?.FullWidth ?? 0)); } Debug.Assert(originalToken.ToFullString() == result.ToFullString()); // yield from text equals yield from node return result; - void rescanInterpolation(out Lexer.InterpolatedStringKind kind, out SyntaxDiagnosticInfo error, out Range openQuoteRange, ArrayBuilder interpolations, out Range closeQuoteRange) + void rescanInterpolation(out Lexer.InterpolatedStringKind kind, out SyntaxDiagnosticInfo? error, out Range openQuoteRange, ArrayBuilder interpolations, out Range closeQuoteRange) { using var tempLexer = new Lexer(SourceText.From(originalText), this.Options, allowPreprocessorDirectives: false); var info = default(Lexer.TokenInfo); tempLexer.ScanInterpolatedStringLiteralTop(ref info, out error, out kind, out openQuoteRange, interpolations, out closeQuoteRange); } - SyntaxToken getOpenQuote(Range openQuoteRange) + SyntaxToken getOpenQuote() { - var openQuoteText = originalText[openQuoteRange]; return SyntaxFactory.Token( originalToken.GetLeadingTrivia(), - kind is Lexer.InterpolatedStringKind.Verbatim ? SyntaxKind.InterpolatedVerbatimStringStartToken : SyntaxKind.InterpolatedStringStartToken, - openQuoteText, openQuoteText, trailing: null); + kind switch + { + Lexer.InterpolatedStringKind.Normal => SyntaxKind.InterpolatedStringStartToken, + Lexer.InterpolatedStringKind.Verbatim => SyntaxKind.InterpolatedVerbatimStringStartToken, + Lexer.InterpolatedStringKind.SingleLineRaw => SyntaxKind.InterpolatedSingleLineRawStringStartToken, + Lexer.InterpolatedStringKind.MultiLineRaw => SyntaxKind.InterpolatedMultiLineRawStringStartToken, + _ => throw ExceptionUtilities.UnexpectedValue(kind), + }, + originalText[openQuoteRange], + trailing: null); } - CodeAnalysis.Syntax.InternalSyntax.SyntaxList getContent(ArrayBuilder interpolations) + CodeAnalysis.Syntax.InternalSyntax.SyntaxList getContent(ReadOnlySpan originalTextSpan) { + var content = PooledStringBuilder.GetInstance(); var builder = _pool.Allocate(); - if (interpolations.Count == 0) + var indentationWhitespace = needsDedentation ? getIndentationWhitespace(originalTextSpan) : default; + + var currentContentStart = openQuoteRange.End; + for (var i = 0; i < interpolations.Count; i++) { - // In the special case when there are no interpolations, we just construct a format string - // with no inserts. We must still use String.Format to get its handling of escapes such as {{, - // so we still treat it as a composite format string. - var text = originalText[new Range(openQuoteRange.End, closeQuoteRange.Start)]; - if (text.Length > 0) - { - builder.Add(SyntaxFactory.InterpolatedStringText(MakeInterpolatedStringTextToken(text, kind))); - } + var interpolation = interpolations[i]; + + // Add a token for text preceding the interpolation + builder.Add(makeContent( + indentationWhitespace, content, isFirst: i == 0, isLast: false, + originalTextSpan[currentContentStart..interpolation.OpenBraceRange.Start])); + + builder.Add(ParseInterpolation(this.Options, originalText, interpolation, kind)); + currentContentStart = interpolation.CloseBraceRange.End; } - else + + // Add a token for text following the last interpolation + builder.Add(makeContent( + indentationWhitespace, content, isFirst: interpolations.Count == 0, isLast: true, + originalTextSpan[currentContentStart..closeQuoteRange.Start])); + + CodeAnalysis.Syntax.InternalSyntax.SyntaxList result = builder; + _pool.Free(builder); + content.Free(); + return result; + } + + // Gets the indentation whitespace from the last line of a multi-line raw literal. + ReadOnlySpan getIndentationWhitespace(ReadOnlySpan originalTextSpan) + { + // The content we want to create text token out of. Effectively, what is in the text sections + // minus leading whitespace. + var closeQuoteText = originalTextSpan[closeQuoteRange]; + + // A multi-line raw interpolation without errors always ends with a new-line, some number of spaces, and + // the quotes. So it's safe to just pull off the first two characters here to find where the + // newline-ends. + var afterNewLine = SlidingTextWindow.GetNewLineWidth(closeQuoteText[0], closeQuoteText[1]); + var afterWhitespace = SkipWhitespace(closeQuoteText, afterNewLine); + + Debug.Assert(closeQuoteText[afterWhitespace] == '"'); + return closeQuoteText[afterNewLine..afterWhitespace]; + } + + InterpolatedStringContentSyntax? makeContent( + ReadOnlySpan indentationWhitespace, StringBuilder content, bool isFirst, bool isLast, ReadOnlySpan text) + { + if (text.Length == 0) + return null; + + // If we're not dedenting then just make a standard interpolated text token. Also, we can short-circuit + // if the indentation whitespace is empty (nothing to dedent in that case). + if (!needsDedentation || indentationWhitespace.IsEmpty) + return SyntaxFactory.InterpolatedStringText(MakeInterpolatedStringTextToken(kind, text.ToString())); + + content.Clear(); + var currentIndex = 0; + + // If we're not processing the first content chunk, then we must be processing a chunk that came after + // an interpolation. In that case, we need to consume up through the next newline of that chunk as + // content that is not subject to dedentation. + if (!isFirst) + currentIndex = ConsumeRemainingContentThroughNewLine(content, text, currentIndex); + + // We're either the first item, or we consumed up through a newline from the previous line. We're + // definitely at the start of a new line (or at the end). Regardless, we want to consume each + // successive line, making sure its indentation is correct. + + // Consume one line at a time. + SyntaxDiagnosticInfo? indentationError = null; + while (currentIndex < text.Length) { - for (int i = 0; i < interpolations.Count; i++) + var lineStartPosition = currentIndex; + + // Only bother reporting a single indentation error on a text chunk. + if (indentationError == null) { - var interpolation = interpolations[i]; + currentIndex = SkipWhitespace(text, currentIndex); + var currentLineWhitespace = text[lineStartPosition..currentIndex]; - // Add a token for text preceding the interpolation - var text = originalText[new Range( - i == 0 ? openQuoteRange.End : interpolations[i - 1].CloseBraceRange.End, - interpolation.OpenBraceRange.Start)]; - if (text.Length > 0) + if (!currentLineWhitespace.StartsWith(indentationWhitespace)) { - builder.Add(SyntaxFactory.InterpolatedStringText(MakeInterpolatedStringTextToken(text, kind))); + // We have a line where the indentation of that line isn't a prefix of indentation + // whitespace. + // + // If we're not on a blank line then this is bad. That's a content line that doesn't start + // with the indentation whitespace. If we are on a blank line then it's ok if the whitespace + // we do have is a prefix of the indentation whitespace. + var isBlankLine = (currentIndex == text.Length && isLast) || (currentIndex < text.Length && SyntaxFacts.IsNewLine(text[currentIndex])); + var isLegalBlankLine = isBlankLine && indentationWhitespace.StartsWith(currentLineWhitespace); + if (!isLegalBlankLine) + { + // Specialized error message if this is a spacing difference. + if (CheckForSpaceDifference( + currentLineWhitespace, indentationWhitespace, + out var currentLineWhitespaceChar, out var indentationWhitespaceChar)) + { + indentationError ??= MakeError( + lineStartPosition, + width: currentIndex - lineStartPosition, + ErrorCode.ERR_LineContainsDifferentWhitespace, + currentLineWhitespaceChar, indentationWhitespaceChar); + } + else + { + indentationError ??= MakeError( + lineStartPosition, + width: currentIndex - lineStartPosition, + ErrorCode.ERR_LineDoesNotStartWithSameWhitespace); + } + } } - - builder.Add(ParseInterpolation(this.Options, originalText, interpolation, kind)); } - // Add a token for text following the last interpolation - var lastText = originalText[new Range(interpolations[^1].CloseBraceRange.End, closeQuoteRange.Start)]; - if (lastText.Length > 0) - { - builder.Add(SyntaxFactory.InterpolatedStringText(MakeInterpolatedStringTextToken(lastText, kind))); - } + // Skip the leading whitespace that matches the terminator line and add any text after that to our content. + currentIndex = Math.Min(currentIndex, lineStartPosition + indentationWhitespace.Length); + currentIndex = ConsumeRemainingContentThroughNewLine(content, text, currentIndex); } - CodeAnalysis.Syntax.InternalSyntax.SyntaxList result = builder; - _pool.Free(builder); - return result; + // if we ran into any errors, don't give this item any special value. It just has the value of our actual text. + var textString = text.ToString(); + var valueString = indentationError != null ? textString : content.ToString(); + + var node = SyntaxFactory.InterpolatedStringText( + SyntaxFactory.Literal(leading: null, textString, SyntaxKind.InterpolatedStringTextToken, valueString, trailing: null)); + + return indentationError != null + ? node.WithDiagnosticsGreen(new[] { indentationError }) + : node; } - SyntaxToken getCloseQuote(Range openQuoteRange) + SyntaxToken getCloseQuote() { // Make a token for the close quote " (even if it was missing) - var closeQuoteText = originalText[closeQuoteRange]; - return closeQuoteText == "" - ? SyntaxFactory.MissingToken(leading: null, SyntaxKind.InterpolatedStringEndToken, trailing: originalToken.GetTrailingTrivia()) - : SyntaxFactory.Token(leading: null, SyntaxKind.InterpolatedStringEndToken, closeQuoteText, closeQuoteText, originalToken.GetTrailingTrivia()); + return TokenOrMissingToken( + leading: null, + kind switch + { + Lexer.InterpolatedStringKind.Normal => SyntaxKind.InterpolatedStringEndToken, + Lexer.InterpolatedStringKind.Verbatim => SyntaxKind.InterpolatedStringEndToken, + Lexer.InterpolatedStringKind.SingleLineRaw => SyntaxKind.InterpolatedRawStringEndToken, + Lexer.InterpolatedStringKind.MultiLineRaw => SyntaxKind.InterpolatedRawStringEndToken, + _ => throw ExceptionUtilities.UnexpectedValue(kind), + }, + originalText[closeQuoteRange], + originalToken.GetTrailingTrivia()); } } + private static bool CheckForSpaceDifference( + ReadOnlySpan currentLineWhitespace, + ReadOnlySpan indentationLineWhitespace, + [NotNullWhen(true)] out string? currentLineMessage, + [NotNullWhen(true)] out string? indentationLineMessage) + { + for (int i = 0, n = Math.Min(currentLineWhitespace.Length, indentationLineWhitespace.Length); i < n; i++) + { + var currentLineChar = currentLineWhitespace[i]; + var indentationLineChar = indentationLineWhitespace[i]; + + if (currentLineChar != indentationLineChar && + SyntaxFacts.IsWhitespace(currentLineChar) && + SyntaxFacts.IsWhitespace(indentationLineChar)) + { + currentLineMessage = Lexer.CharToString(currentLineChar); + indentationLineMessage = Lexer.CharToString(indentationLineChar); + return true; + } + } + + currentLineMessage = null; + indentationLineMessage = null; + return false; + } + + private static SyntaxToken TokenOrMissingToken(GreenNode? leading, SyntaxKind kind, string text, GreenNode? trailing) + => text == "" + ? SyntaxFactory.MissingToken(leading, kind, trailing) + : SyntaxFactory.Token(leading, kind, text, trailing); + + private static int SkipWhitespace(ReadOnlySpan text, int currentIndex) + { + while (currentIndex < text.Length && SyntaxFacts.IsWhitespace(text[currentIndex])) + currentIndex++; + return currentIndex; + } + + private static int ConsumeRemainingContentThroughNewLine(StringBuilder content, ReadOnlySpan text, int currentIndex) + { + var start = currentIndex; + while (currentIndex < text.Length) + { + var ch = text[currentIndex]; + if (!SyntaxFacts.IsNewLine(ch)) + { + currentIndex++; + continue; + } + + currentIndex += SlidingTextWindow.GetNewLineWidth(ch, currentIndex + 1 < text.Length ? text[currentIndex + 1] : '\0'); + break; + } + + var slice = text[start..currentIndex]; +#if NETCOREAPP + content.Append(slice); +#else + unsafe + { + fixed (char* pointer = slice) + content.Append(pointer, slice.Length); + } +#endif + return currentIndex; + } + private static InterpolationSyntax ParseInterpolation( CSharpParseOptions options, string text, @@ -141,24 +322,22 @@ private static InterpolationSyntax ParseInterpolation( // will be used to parse out the expression of the interpolation. // // The parsing of the open brace, close brace and colon is specially handled in ParseInterpolation below. - var expressionText = text[new Range( - interpolation.OpenBraceRange.End, - interpolation.HasColon ? interpolation.ColonRange.Start : interpolation.CloseBraceRange.Start)]; + var followingRange = interpolation.HasColon ? interpolation.ColonRange : interpolation.CloseBraceRange; + var expressionText = text[interpolation.OpenBraceRange.End..followingRange.Start]; using var tempLexer = new Lexer(SourceText.From(expressionText), options, allowPreprocessorDirectives: false, interpolationFollowedByColon: interpolation.HasColon); // First grab any trivia right after the {, it will be trailing trivia for the { token. var openTokenTrailingTrivia = tempLexer.LexSyntaxTrailingTrivia().Node; - var openTokenText = text[interpolation.OpenBraceRange]; // Now create a parser to actually handle the expression portion of the interpolation using var tempParser = new LanguageParser(tempLexer, oldTree: null, changes: null); var result = tempParser.ParseInterpolation( text, interpolation, kind, - SyntaxFactory.Token(leading: null, SyntaxKind.OpenBraceToken, openTokenText, openTokenText, openTokenTrailingTrivia)); + SyntaxFactory.Token(leading: null, SyntaxKind.OpenBraceToken, text[interpolation.OpenBraceRange], openTokenTrailingTrivia)); - Debug.Assert(text[new Range(interpolation.OpenBraceRange.Start, interpolation.CloseBraceRange.End)] == result.ToFullString()); // yield from text equals yield from node + Debug.Assert(text[interpolation.OpenBraceRange.Start..interpolation.CloseBraceRange.End] == result.ToFullString()); // yield from text equals yield from node return result; } @@ -171,9 +350,13 @@ private InterpolationSyntax ParseInterpolation( var (expression, alignment) = getExpressionAndAlignment(); var (format, closeBraceToken) = getFormatAndCloseBrace(); - return SyntaxFactory.Interpolation(openBraceToken, expression, alignment, format, closeBraceToken); + var result = SyntaxFactory.Interpolation(openBraceToken, expression, alignment, format, closeBraceToken); +#if DEBUG + Debug.Assert(text[interpolation.OpenBraceRange.Start..interpolation.CloseBraceRange.End] == result.ToFullString()); // yield from text equals yield from node +#endif + return result; - (ExpressionSyntax expression, InterpolationAlignmentClauseSyntax alignment) getExpressionAndAlignment() + (ExpressionSyntax expression, InterpolationAlignmentClauseSyntax? alignment) getExpressionAndAlignment() { var expression = this.ParseExpressionCore(); @@ -188,31 +371,29 @@ private InterpolationSyntax ParseInterpolation( return (expression, alignment); } - (InterpolationFormatClauseSyntax format, SyntaxToken closeBraceToken) getFormatAndCloseBrace() + (InterpolationFormatClauseSyntax? format, SyntaxToken closeBraceToken) getFormatAndCloseBrace() { var leading = this.CurrentToken.GetLeadingTrivia(); if (interpolation.HasColon) { - var colonText = text[interpolation.ColonRange]; - var formatText = text[new Range(interpolation.ColonRange.End, interpolation.CloseBraceRange.Start)]; var format = SyntaxFactory.InterpolationFormatClause( - SyntaxFactory.Token(leading, SyntaxKind.ColonToken, colonText, colonText, trailing: null), - MakeInterpolatedStringTextToken(formatText, kind)); - return (format, getInterpolationCloseBraceToken(leading: null)); + SyntaxFactory.Token(leading, SyntaxKind.ColonToken, text[interpolation.ColonRange], trailing: null), + MakeInterpolatedStringTextToken(kind, text[interpolation.ColonRange.End..interpolation.CloseBraceRange.Start])); + return (format, getInterpolationCloseToken(leading: null)); } else { - return (format: null, getInterpolationCloseBraceToken(leading)); + return (format: null, getInterpolationCloseToken(leading)); } } - SyntaxToken getInterpolationCloseBraceToken(GreenNode leading) + SyntaxToken getInterpolationCloseToken(GreenNode? leading) { - var tokenText = text[interpolation.CloseBraceRange]; - if (tokenText == "") - return SyntaxFactory.MissingToken(leading, SyntaxKind.CloseBraceToken, trailing: null); - - return SyntaxFactory.Token(leading, SyntaxKind.CloseBraceToken, tokenText, tokenText, trailing: null); + return TokenOrMissingToken( + leading, + SyntaxKind.CloseBraceToken, + text[interpolation.CloseBraceRange], + trailing: null); } } @@ -220,32 +401,40 @@ SyntaxToken getInterpolationCloseBraceToken(GreenNode leading) /// Interpret the given raw text from source as an InterpolatedStringTextToken. /// /// The text for the full string literal, including the quotes and contents - /// The kind of the interpolation - private SyntaxToken MakeInterpolatedStringTextToken(string text, Lexer.InterpolatedStringKind kind) + /// The kind of the interpolated string we were processing + private SyntaxToken MakeInterpolatedStringTextToken(Lexer.InterpolatedStringKind kind, string text) { + // with a raw string, we don't do any interpretation of the content. Note: removal of indentation is + // handled already in splitContent + if (kind is Lexer.InterpolatedStringKind.SingleLineRaw or Lexer.InterpolatedStringKind.MultiLineRaw) + return SyntaxFactory.Literal(leading: null, text, SyntaxKind.InterpolatedStringTextToken, text, trailing: null); + + Debug.Assert(kind is Lexer.InterpolatedStringKind.Normal or Lexer.InterpolatedStringKind.Verbatim); + + // For a normal/verbatim piece of content, process the inner content as if it was in a corresponding + // *non*-interpolated string to get the correct meaning of all the escapes/diagnostics within. var prefix = kind is Lexer.InterpolatedStringKind.Verbatim ? "@\"" : "\""; var fakeString = prefix + text + "\""; - using var tempLexer = new Lexer(Text.SourceText.From(fakeString), this.Options, allowPreprocessorDirectives: false); - + using var tempLexer = new Lexer(SourceText.From(fakeString), this.Options, allowPreprocessorDirectives: false); var mode = LexerMode.Syntax; var token = tempLexer.Lex(ref mode); Debug.Assert(token.Kind == SyntaxKind.StringLiteralToken); var result = SyntaxFactory.Literal(leading: null, text, SyntaxKind.InterpolatedStringTextToken, token.ValueText, trailing: null); if (token.ContainsDiagnostics) - { result = result.WithDiagnosticsGreen(MoveDiagnostics(token.GetDiagnostics(), -prefix.Length)); - } return result; } private static DiagnosticInfo[] MoveDiagnostics(DiagnosticInfo[] infos, int offset) { - var builder = ArrayBuilder.GetInstance(); + Debug.Assert(infos.Length > 0); + var builder = ArrayBuilder.GetInstance(infos.Length); foreach (var info in infos) { - var sd = info as SyntaxDiagnosticInfo; - builder.Add(sd?.WithOffset(sd.Offset + offset) ?? info); + // This cast should always be safe. We are only moving diagnostics produced on syntax nodes and tokens. + var sd = (SyntaxDiagnosticInfo)info; + builder.Add(sd.WithOffset(sd.Offset + offset)); } return builder.ToArrayAndFree(); diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer.cs b/src/Compilers/CSharp/Portable/Parser/Lexer.cs index 74ef7e7134761..ebf15fc6cac32 100644 --- a/src/Compilers/CSharp/Portable/Parser/Lexer.cs +++ b/src/Compilers/CSharp/Portable/Parser/Lexer.cs @@ -386,6 +386,8 @@ private SyntaxToken Create(ref TokenInfo info, SyntaxListBuilder leading, Syntax token = SyntaxFactory.Literal(leadingNode, info.Text, info.Kind, info.Text, trailingNode); break; case SyntaxKind.StringLiteralToken: + case SyntaxKind.SingleLineRawStringLiteralToken: + case SyntaxKind.MultiLineRawStringLiteralToken: token = SyntaxFactory.Literal(leadingNode, info.Text, info.Kind, info.StringValue, trailingNode); break; case SyntaxKind.CharacterLiteralToken: @@ -765,7 +767,8 @@ private void ScanSyntaxToken(ref TokenInfo info) if (!this.TryScanAtStringToken(ref info) && !this.ScanIdentifierOrKeyword(ref info)) { - TextWindow.AdvanceChar(); + Debug.Assert(TextWindow.PeekChar() == '@'); + this.ConsumeAtSignSequence(); info.Text = TextWindow.GetText(intern: true); this.AddError(ErrorCode.ERR_ExpectedVerbatimLiteral); } @@ -928,13 +931,21 @@ private bool TryScanAtStringToken(ref TokenInfo info) { Debug.Assert(TextWindow.PeekChar() == '@'); - if (TextWindow.PeekChar(1) == '"') + var index = 0; + while (TextWindow.PeekChar(index) == '@') + { + index++; + } + + if (TextWindow.PeekChar(index) == '"') { + // @" this.ScanVerbatimStringLiteral(ref info); return true; } - else if (TextWindow.PeekChar(1) == '$' && TextWindow.PeekChar(2) == '"') + else if (TextWindow.PeekChar(index) == '$') { + // @$" this.ScanInterpolatedStringLiteral(ref info); return true; } @@ -946,8 +957,24 @@ private bool TryScanInterpolatedString(ref TokenInfo info) { Debug.Assert(TextWindow.PeekChar() == '$'); - if (TextWindow.PeekChar(1) == '"' || - (TextWindow.PeekChar(1) == '@' && TextWindow.PeekChar(2) == '"')) + if (TextWindow.PeekChar(1) == '$') + { + // $$ - definitely starts a raw interpolated string. + this.ScanInterpolatedStringLiteral(ref info); + return true; + } + else if (TextWindow.PeekChar(1) == '@' && TextWindow.PeekChar(2) == '@') + { + // $@@ - Error case. Detect if user is trying to user verbatim and raw interpolations together. + this.ScanInterpolatedStringLiteral(ref info); + return true; + } + else if (TextWindow.PeekChar(1) == '"') + { + this.ScanInterpolatedStringLiteral(ref info); + return true; + } + else if (TextWindow.PeekChar(1) == '@') { this.ScanInterpolatedStringLiteral(ref info); return true; @@ -1678,14 +1705,15 @@ private bool ScanIdentifier_SlowPath(ref TokenInfo info) int start = TextWindow.Position; this.ResetIdentBuffer(); - info.IsVerbatim = TextWindow.PeekChar() == '@'; - if (info.IsVerbatim) + while (TextWindow.PeekChar() == '@') { TextWindow.AdvanceChar(); } - bool isObjectAddress = false; + var atCount = TextWindow.Position - start; + info.IsVerbatim = atCount > 0; + bool isObjectAddress = false; while (true) { char surrogateCharacter = SlidingTextWindow.InvalidCharacter; @@ -1921,6 +1949,11 @@ private bool ScanIdentifier_SlowPath(ref TokenInfo info) this.GetValueUInt64(valueText, isHex: true, isBinary: false); } + if (atCount >= 2) + { + this.AddError(start, atCount, ErrorCode.ERR_IllegalAtSequence); + } + return true; } diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer_RawStringLiteral.cs b/src/Compilers/CSharp/Portable/Parser/Lexer_RawStringLiteral.cs new file mode 100644 index 0000000000000..f7d088019c734 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Parser/Lexer_RawStringLiteral.cs @@ -0,0 +1,424 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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 System.Diagnostics.CodeAnalysis; +using System.Text; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax +{ + internal partial class Lexer + { + /// The number of quotes that were consumed + private int ConsumeCharSequence(char ch) + { + var start = TextWindow.Position; + while (TextWindow.PeekChar() == ch) + TextWindow.AdvanceChar(); + + return TextWindow.Position - start; + } + + private int ConsumeQuoteSequence() + => ConsumeCharSequence('"'); + + private int ConsumeDollarSignSequence() + => ConsumeCharSequence('$'); + + private int ConsumeAtSignSequence() + => ConsumeCharSequence('@'); + + private int ConsumeOpenBraceSequence() + => ConsumeCharSequence('{'); + + private int ConsumeCloseBraceSequence() + => ConsumeCharSequence('}'); + + private void ConsumeWhitespace(StringBuilder? builder) + { + while (true) + { + var ch = TextWindow.PeekChar(); + if (!SyntaxFacts.IsWhitespace(ch)) + break; + + builder?.Append(ch); + TextWindow.AdvanceChar(); + } + } + + private bool IsAtEndOfText(char currentChar) + => currentChar == SlidingTextWindow.InvalidCharacter && TextWindow.IsReallyAtEnd(); + + private void ScanRawStringLiteral(ref TokenInfo info) + { + _builder.Length = 0; + + var startingQuoteCount = ConsumeQuoteSequence(); + + Debug.Assert(startingQuoteCount >= 3); + + // Keep consuming whitespace after the initial quote sequence. + ConsumeWhitespace(builder: null); + + if (SyntaxFacts.IsNewLine(TextWindow.PeekChar())) + { + // Past the initial whitespace, and we hit a newline, this is a multi line raw string literal. + ScanMultiLineRawStringLiteral(ref info, startingQuoteCount); + } + else + { + // Past the initial whitespace, and we hit anything else, this is a single line raw string literal. + ScanSingleLineRawStringLiteral(ref info, startingQuoteCount); + } + + // If we encounter any errors while scanning this raw string then we can't really determine the true + // value of the string. So just do what we do with the normal strings and treat the contents as the + // value from after the starting quote to the current position. Note that for normal strings this will + // have interpreted things like escape sequences. However, as we're a raw string and there are no + // escapes, we can just grab the text block directly. This does mean that things like leading indentation + // will not be stripped, and that multiline raw strings will contain the contents of their first line. + // However, as this is error code anyways, the interpretation of the value is fine for us to define + // however we want. The user can (and should) check for the presence of diagnostics before blindly + // trusting the contents. + if (this.HasErrors) + { + var afterStartDelimiter = TextWindow.LexemeStartPosition + startingQuoteCount; + var valueLength = TextWindow.Position - afterStartDelimiter; + + info.StringValue = TextWindow.GetText( + position: afterStartDelimiter, + length: valueLength, + intern: true); + } + else + { + // If we didn't have an error, the subroutines better have set the string value for this literal. + Debug.Assert(info.StringValue != null); + } + + info.Text = TextWindow.GetText(intern: true); + } + + private void ScanSingleLineRawStringLiteral(ref TokenInfo info, int startingQuoteCount) + { + info.Kind = SyntaxKind.SingleLineRawStringLiteralToken; + + while (true) + { + var currentChar = TextWindow.PeekChar(); + + // See if we reached the end of the line or file before hitting the end. + if (SyntaxFacts.IsNewLine(currentChar)) + { + this.AddError(TextWindow.Position, width: TextWindow.GetNewLineWidth(), ErrorCode.ERR_UnterminatedRawString); + return; + } + else if (IsAtEndOfText(currentChar)) + { + this.AddError(TextWindow.Position, width: 0, ErrorCode.ERR_UnterminatedRawString); + return; + } + + if (currentChar != '"') + { + // anything not a quote sequence just moves it forward. + TextWindow.AdvanceChar(); + continue; + } + + var beforeEndDelimiter = TextWindow.Position; + var currentQuoteCount = ConsumeQuoteSequence(); + + // A raw string literal starting with some number of quotes can contain a quote sequence with fewer quotes. + if (currentQuoteCount < startingQuoteCount) + continue; + + // A raw string could never be followed by another string. So once we've consumed all the closing quotes + // if we have any more closing quotes then that's an error we can give a message for. + if (currentQuoteCount > startingQuoteCount) + { + var excessQuoteCount = currentQuoteCount - startingQuoteCount; + this.AddError( + position: TextWindow.Position - excessQuoteCount, + width: excessQuoteCount, + ErrorCode.ERR_TooManyQuotesForRawString); + } + + // We have enough quotes to finish this string at this point. + var afterStartDelimiter = TextWindow.LexemeStartPosition + startingQuoteCount; + var valueLength = beforeEndDelimiter - afterStartDelimiter; + + info.StringValue = TextWindow.GetText( + position: afterStartDelimiter, + length: valueLength, + intern: true); + return; + } + } + + private void ScanMultiLineRawStringLiteral(ref TokenInfo info, int startingQuoteCount) + { + info.Kind = SyntaxKind.MultiLineRawStringLiteralToken; + + // The indentation-whitespace computed from the very last line of the raw string literal + var indentationWhitespace = PooledStringBuilder.GetInstance(); + + // The leading whitespace of whatever line we are currently on. + var currentLineWhitespace = PooledStringBuilder.GetInstance(); + try + { + // Do the first pass, finding the end of the raw string, and determining the 'indentation whitespace' + // that must be complimentary with all content lines of the raw string literal. + var afterStartDelimiter = TextWindow.Position; + Debug.Assert(SyntaxFacts.IsNewLine(TextWindow.PeekChar())); + + var contentLineCount = 0; + while (ScanMultiLineRawStringLiteralLine(startingQuoteCount, indentationWhitespace.Builder)) + contentLineCount++; + + // If the initial scan failed then just bail out without a constant value. + if (this.HasErrors) + return; + + // The trivial raw string literal is not legal in the language. + if (contentLineCount == 0) + { + this.AddError( + position: TextWindow.Position - startingQuoteCount, + width: startingQuoteCount, + ErrorCode.ERR_RawStringMustContainContent); + return; + } + + // Now, do the second pass, building up the literal value. This may produce an error as well if the + // indentation whitespace of the lines isn't complimentary. + + // Reset us to right after the starting delimiter. Note: if we fail to generate a constant value we'll + // ensure that we reset back to the original end we scanned to above. + var tokenEnd = TextWindow.Position; + TextWindow.Reset(afterStartDelimiter); + Debug.Assert(SyntaxFacts.IsNewLine(TextWindow.PeekChar())); + + for (var currentLine = 0; currentLine < contentLineCount; currentLine++) + { + AddMultiLineRawStringLiteralLineContents( + indentationWhitespace.Builder, + currentLineWhitespace.Builder, + firstContentLine: currentLine == 0); + + // If processing the line produced errors, then bail out from continued processing. + if (this.HasErrors) + break; + } + + info.StringValue = this.HasErrors ? "" : TextWindow.Intern(_builder); + + // Make sure that even if we fail to determine the constant content value of the string that + // we still consume all the way to original end that we computed. + TextWindow.Reset(tokenEnd); + } + finally + { + indentationWhitespace.Free(); + currentLineWhitespace.Free(); + } + } + + private bool ScanMultiLineRawStringLiteralLine( + int startingQuoteCount, StringBuilder indentationWhitespace) + { + TextWindow.AdvancePastNewLine(); + + indentationWhitespace.Clear(); + ConsumeWhitespace(indentationWhitespace); + + // after the whitespace see if this the line that ends the multiline literal. + var currentQuoteCount = ConsumeQuoteSequence(); + if (currentQuoteCount >= startingQuoteCount) + { + // A raw string could never be followed by another string. So once we've consumed all the closing quotes + // if we have any more closing quotes then that's an error we can give a message for. + if (currentQuoteCount > startingQuoteCount) + { + var excessQuoteCount = currentQuoteCount - startingQuoteCount; + this.AddError( + position: TextWindow.Position - excessQuoteCount, + width: excessQuoteCount, + ErrorCode.ERR_TooManyQuotesForRawString); + } + + // Done scanning lines. + return false; + } + + // We're not on the terminating line. Consume a normal content line. Eat to the end of line (or file in the + // case of errors). + while (true) + { + var currentChar = TextWindow.PeekChar(); + if (IsAtEndOfText(currentChar)) + { + this.AddError(TextWindow.Position, width: 0, ErrorCode.ERR_UnterminatedRawString); + return false; + } + + if (SyntaxFacts.IsNewLine(currentChar)) + return true; + + if (currentChar == '"') + { + // Don't allow a content line to contain a quote sequence that looks like a delimiter (or longer) + currentQuoteCount = ConsumeQuoteSequence(); + if (currentQuoteCount >= startingQuoteCount) + { + this.AddError( + position: TextWindow.Position - currentQuoteCount, + width: currentQuoteCount, + ErrorCode.ERR_RawStringDelimiterOnOwnLine); + return false; + } + } + else + { + TextWindow.AdvanceChar(); + } + } + } + + private void AddMultiLineRawStringLiteralLineContents( + StringBuilder indentationWhitespace, + StringBuilder currentLineWhitespace, + bool firstContentLine) + { + Debug.Assert(SyntaxFacts.IsNewLine(TextWindow.PeekChar())); + + var newLineWidth = TextWindow.GetNewLineWidth(); + for (var i = 0; i < newLineWidth; i++) + { + // the initial newline in `""" \r\n` is not added to the contents. + if (!firstContentLine) + _builder.Append(TextWindow.PeekChar()); + + TextWindow.AdvanceChar(); + } + + var lineStartPosition = TextWindow.Position; + currentLineWhitespace.Clear(); + ConsumeWhitespace(currentLineWhitespace); + + if (!StartsWith(currentLineWhitespace, indentationWhitespace)) + { + // We have a line where the indentation of that line isn't a prefix of indentation + // whitespace. + // + // If we're not on a blank line then this is bad. That's a content line that doesn't start + // with the indentation whitespace. If we are on a blank line then it's ok if the whitespace + // we do have is a prefix of the indentation whitespace. + var isBlankLine = SyntaxFacts.IsNewLine(TextWindow.PeekChar()); + var isLegalBlankLine = isBlankLine && StartsWith(indentationWhitespace, currentLineWhitespace); + if (!isLegalBlankLine) + { + // Specialized error message if this is a spacing difference. + if (CheckForSpaceDifference( + currentLineWhitespace, indentationWhitespace, + out var currentLineWhitespaceChar, out var indentationWhitespaceChar)) + { + this.AddError( + lineStartPosition, + width: TextWindow.Position - lineStartPosition, + ErrorCode.ERR_LineContainsDifferentWhitespace, + currentLineWhitespaceChar, indentationWhitespaceChar); + } + else + { + this.AddError( + lineStartPosition, + width: TextWindow.Position - lineStartPosition, + ErrorCode.ERR_LineDoesNotStartWithSameWhitespace); + } + return; + } + } + + // Skip the leading whitespace that matches the terminator line and add any whitespace past that to the + // string value. Note: if the current line is shorter than the indentation whitespace, this will + // intentionally copy nothing. +#if NETCOREAPP + _builder.Append(currentLineWhitespace, startIndex: indentationWhitespace.Length, count: Math.Max(0, currentLineWhitespace.Length - indentationWhitespace.Length)); +#else + for (var i = indentationWhitespace.Length; i < currentLineWhitespace.Length; i++) + _builder.Append(currentLineWhitespace[i]); +#endif + + // Consume up to the next new line. + while (true) + { + var currentChar = TextWindow.PeekChar(); + + if (SyntaxFacts.IsNewLine(currentChar)) + return; + + _builder.Append(currentChar); + TextWindow.AdvanceChar(); + } + } + + private static bool CheckForSpaceDifference( + StringBuilder currentLineWhitespace, + StringBuilder indentationLineWhitespace, + [NotNullWhen(true)] out string? currentLineMessage, + [NotNullWhen(true)] out string? indentationLineMessage) + { + for (int i = 0, n = Math.Min(currentLineWhitespace.Length, indentationLineWhitespace.Length); i < n; i++) + { + var currentLineChar = currentLineWhitespace[i]; + var indentationLineChar = indentationLineWhitespace[i]; + + if (currentLineChar != indentationLineChar && + SyntaxFacts.IsWhitespace(currentLineChar) && + SyntaxFacts.IsWhitespace(indentationLineChar)) + { + currentLineMessage = CharToString(currentLineChar); + indentationLineMessage = CharToString(indentationLineChar); + return true; + } + } + + currentLineMessage = null; + indentationLineMessage = null; + return false; + } + + public static string CharToString(char ch) + { + return ch switch + { + '\t' => @"\t", + '\v' => @"\v", + '\f' => @"\f", + _ => @$"\u{(int)ch:x4}", + }; + } + + /// + /// Returns true if starts with . + /// + private static bool StartsWith(StringBuilder sb, StringBuilder value) + { + if (sb.Length < value.Length) + return false; + + for (int i = 0; i < value.Length; i++) + { + if (sb[i] != value[i]) + return false; + } + + return true; + } + } +} diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer_StringLiteral.cs b/src/Compilers/CSharp/Portable/Parser/Lexer_StringLiteral.cs index a8e476ce3ab12..92ff794273d83 100644 --- a/src/Compilers/CSharp/Portable/Parser/Lexer_StringLiteral.cs +++ b/src/Compilers/CSharp/Portable/Parser/Lexer_StringLiteral.cs @@ -16,6 +16,22 @@ private void ScanStringLiteral(ref TokenInfo info, bool inDirective) var quoteCharacter = TextWindow.PeekChar(); Debug.Assert(quoteCharacter is '\'' or '"'); + if (TextWindow.PeekChar() == '"' && + TextWindow.PeekChar(1) == '"' && + TextWindow.PeekChar(2) == '"') + { + ScanRawStringLiteral(ref info); + if (inDirective) + { + // Reinterpret this as just a string literal so that the directive parser can consume this. + // But report this is illegal so that the user knows to fix this up to be a normal string. + info.Kind = SyntaxKind.StringLiteralToken; + info.StringValue = ""; + this.AddError(ErrorCode.ERR_RawStringNotInDirectives); + } + return; + } + TextWindow.AdvanceChar(); _builder.Length = 0; @@ -147,10 +163,22 @@ private char ScanEscapeSequence(out char surrogateCharacter) private void ScanVerbatimStringLiteral(ref TokenInfo info) { + Debug.Assert(TextWindow.PeekChar() == '@'); _builder.Length = 0; - Debug.Assert(TextWindow.PeekChar() == '@' && TextWindow.PeekChar(1) == '"'); - TextWindow.AdvanceChar(2); + var start = TextWindow.Position; + while (TextWindow.PeekChar() == '@') + { + TextWindow.AdvanceChar(); + } + + if (TextWindow.Position - start >= 2) + { + this.AddError(start, width: TextWindow.Position - start, ErrorCode.ERR_IllegalAtSequence); + } + + Debug.Assert(TextWindow.PeekChar() == '"'); + TextWindow.AdvanceChar(); while (true) { @@ -211,7 +239,6 @@ private void ScanInterpolatedStringLiteral(ref TokenInfo info) openQuoteRange: out _, interpolations: null, closeQuoteRange: out _); - this.AddError(error); } @@ -251,13 +278,21 @@ internal static SyntaxToken RescanInterpolatedString(InterpolatedStringExpressio internal enum InterpolatedStringKind { /// - /// Normal interpolated string that just starts with $" + /// Normal interpolated string that just starts with $" /// Normal, /// - /// Verbatim interpolated string that starts with $@" or @$" + /// Verbatim interpolated string that starts with $@" or @$" /// Verbatim, + /// + /// Single-line raw interpolated string that starts with at least one $, and at least three "s. + /// + SingleLineRaw, + /// + /// Multi-line raw interpolated string that starts with at least one $, and at least three "s. + /// + MultiLineRaw, } /// @@ -269,8 +304,6 @@ private ref struct InterpolatedStringScanner { private readonly Lexer _lexer; - private readonly InterpolatedStringKind _kind; - /// /// Error encountered while scanning. If we run into an error, then we'll attempt to stop parsing at the /// next potential ending location to prevent compounding the issue. @@ -280,16 +313,11 @@ private ref struct InterpolatedStringScanner public InterpolatedStringScanner(Lexer lexer) { _lexer = lexer; - - _kind = - (_lexer.TextWindow.PeekChar(0), _lexer.TextWindow.PeekChar(1)) is ('$', '@') or ('@', '$') - ? InterpolatedStringKind.Verbatim - : InterpolatedStringKind.Normal; } - private bool IsAtEnd() + private bool IsAtEnd(InterpolatedStringKind kind) { - return IsAtEnd(_kind is InterpolatedStringKind.Verbatim); + return IsAtEnd(allowNewline: kind is InterpolatedStringKind.Verbatim or InterpolatedStringKind.MultiLineRaw); } private bool IsAtEnd(bool allowNewline) @@ -300,7 +328,7 @@ private bool IsAtEnd(bool allowNewline) (ch == SlidingTextWindow.InvalidCharacter && _lexer.TextWindow.IsReallyAtEnd()); } - private void TrySetUnrecoverableError(SyntaxDiagnosticInfo error) + private void TrySetError(SyntaxDiagnosticInfo error) { // only need to record the first error we hit Error ??= error; @@ -312,144 +340,568 @@ internal void ScanInterpolatedStringLiteralTop( ArrayBuilder? interpolations, out Range closeQuoteRange) { - kind = _kind; - ScanInterpolatedStringLiteralStart(out openQuoteRange); - ScanInterpolatedStringLiteralContents(interpolations); - ScanInterpolatedStringLiteralEnd(out closeQuoteRange); + // Scan through the open-quote portion of this literal, determining important information the rest of + // the scanning needs. + var start = _lexer.TextWindow.Position; + var succeeded = ScanOpenQuote(out kind, out var startingDollarSignCount, out var startingQuoteCount); + Debug.Assert(_lexer.TextWindow.Position != start); + + openQuoteRange = start.._lexer.TextWindow.Position; + + if (!succeeded) + { + // Processing the start of this literal didn't give us enough information to proceed. Stop now, + // terminating the string to the furthest point we reached. + closeQuoteRange = _lexer.TextWindow.Position.._lexer.TextWindow.Position; + return; + } + + ScanInterpolatedStringLiteralContents(kind, startingDollarSignCount, startingQuoteCount, interpolations); + ScanInterpolatedStringLiteralEnd(kind, startingQuoteCount, out closeQuoteRange); } - private void ScanInterpolatedStringLiteralStart(out Range openQuoteRange) + /// + /// Number of '$' characters this interpolated string started with. We'll need to see that many '{' in a + /// row to start an interpolation. Any less and we'll treat that as just text. Note if this count is '1' + /// then this is a normal (non-raw) interpolation and `{{` is treated as an escape. + /// + /// Number of '"' characters this interpolated string started with. + /// if we successfully processed the open quote range and can proceed to the + /// rest of the literal. if we were not successful and should stop + /// processing. + private bool ScanOpenQuote( + out InterpolatedStringKind kind, + out int startingDollarSignCount, + out int startingQuoteCount) { // Handles reading the start of the interpolated string literal (up to where the content begins) - var start = _lexer.TextWindow.Position; - if (_kind is InterpolatedStringKind.Verbatim) + var window = _lexer.TextWindow; + var start = window.Position; + + if ((window.PeekChar(0), window.PeekChar(1), window.PeekChar(2)) is ('$', '@', '"') or ('@', '$', '"')) { - // skip past @$ or $@ - _lexer.TextWindow.AdvanceChar(2); + // $@" or @$" + // + // Note: we do not consider $@""" as the start of raw-string (in error conditions) as that's a legal + // verbatim string beginning already. + + kind = InterpolatedStringKind.Verbatim; + startingDollarSignCount = 1; + startingQuoteCount = 1; + window.AdvanceChar(3); + return true; } - else + + if ((window.PeekChar(0), window.PeekChar(1), window.PeekChar(2), window.PeekChar(3)) is + ('$', '"', not '"', _) or ('$', '"', '"', not '"')) { - Debug.Assert(_lexer.TextWindow.PeekChar() == '$'); - _lexer.TextWindow.AdvanceChar(); + // $"... + // $"" + // not $""" + kind = InterpolatedStringKind.Normal; + startingDollarSignCount = 1; + startingQuoteCount = 1; + window.AdvanceChar(2); + return true; } - Debug.Assert(_lexer.TextWindow.PeekChar() == '"'); - _lexer.TextWindow.AdvanceChar(); + // From this point we have either a complete error case that we cannot process further, or a raw literal + // of some sort. + var prefixAtCount = _lexer.ConsumeAtSignSequence(); + startingDollarSignCount = _lexer.ConsumeDollarSignSequence(); + Debug.Assert(startingDollarSignCount > 0); + + var suffixAtCount = _lexer.ConsumeAtSignSequence(); + startingQuoteCount = _lexer.ConsumeQuoteSequence(); + + var totalAtCount = prefixAtCount + suffixAtCount; + + // We should only have gotten here if we had at least two characters that made us think we had an + // interpolated string. Note that we may enter here on just `@@` or `$$` (without seeing anything else), + // so we can't put a stricter bound on this here. + Debug.Assert(totalAtCount + startingDollarSignCount + startingQuoteCount >= 2); + + if (startingQuoteCount == 0) + { + // We have no quotes at all. We cannot continue on as we have no quotes, and thus can't even find + // where the string starts or ends. + TrySetError(_lexer.MakeError(start, window.Position - start, ErrorCode.ERR_StringMustStartWithQuoteCharacter)); + kind = totalAtCount == 1 && startingDollarSignCount == 1 + ? InterpolatedStringKind.Verbatim + : InterpolatedStringKind.SingleLineRaw; + return false; + } + + // @-signs with interpolations are always illegal. Detect these and give a reasonable error message. + // Continue on if we can. + if (totalAtCount > 0) + { + TrySetError(_lexer.MakeError(start, window.Position - start, ErrorCode.ERR_IllegalAtSequence)); + } + + if (startingQuoteCount < 3) + { + // 1-2 quotes present. Not legal. But we can give a good error message and still proceed. + TrySetError(_lexer.MakeError(window.Position - startingQuoteCount, startingQuoteCount, ErrorCode.ERR_NotEnoughQuotesForRawString)); + } - openQuoteRange = new Range(start, _lexer.TextWindow.Position); + // Now see if this was a single-line or multi-line raw literal. + + var afterQuotePosition = window.Position; + _lexer.ConsumeWhitespace(builder: null); + if (SyntaxFacts.IsNewLine(window.PeekChar())) + { + // We had whitespace followed by a newline. That section is considered the open-quote section of + // the literal. + window.AdvancePastNewLine(); + kind = InterpolatedStringKind.MultiLineRaw; + } + else + { + // wasn't multi-line, jump back to right after the quotes as what follows is content and not + // considered part of the open quote. + window.Reset(afterQuotePosition); + kind = InterpolatedStringKind.SingleLineRaw; + } + + return true; } - private void ScanInterpolatedStringLiteralEnd(out Range closeQuoteRange) + private void ScanInterpolatedStringLiteralEnd(InterpolatedStringKind kind, int startingQuoteCount, out Range closeQuoteRange) { // Handles reading the end of the interpolated string literal (after where the content ends) var closeQuotePosition = _lexer.TextWindow.Position; + + if (kind is InterpolatedStringKind.Normal or InterpolatedStringKind.Verbatim) + { + ScanNormalOrVerbatimInterpolatedStringLiteralEnd(kind); + } + else + { + Debug.Assert(kind is InterpolatedStringKind.SingleLineRaw or InterpolatedStringKind.MultiLineRaw); + ScanRawInterpolatedStringLiteralEnd(kind, startingQuoteCount); + } + + // Note: this range may be empty. For example, if we hit the end of a line for a single-line construct, + // or we hit the end of a file for a multi-line construct. + closeQuoteRange = closeQuotePosition.._lexer.TextWindow.Position; + } + + private void ScanNormalOrVerbatimInterpolatedStringLiteralEnd(InterpolatedStringKind kind) + { + Debug.Assert(kind is InterpolatedStringKind.Normal or InterpolatedStringKind.Verbatim); + if (_lexer.TextWindow.PeekChar() != '"') { - Debug.Assert(IsAtEnd()); - int position = IsAtEnd(allowNewline: true) ? _lexer.TextWindow.Position - 1 : _lexer.TextWindow.Position; - TrySetUnrecoverableError(_lexer.MakeError(position, 1, _kind is InterpolatedStringKind.Verbatim ? ErrorCode.ERR_UnterminatedStringLit : ErrorCode.ERR_NewlineInConst)); + // Didn't find a closing quote. We hit the end of a line (in the normal case) or the end of the + // file in the normal/verbatim case. + Debug.Assert(IsAtEnd(kind)); + + TrySetError(_lexer.MakeError( + IsAtEnd(allowNewline: true) ? _lexer.TextWindow.Position - 1 : _lexer.TextWindow.Position, + width: 1, ErrorCode.ERR_UnterminatedStringLit)); } else { // found the closing quote _lexer.TextWindow.AdvanceChar(); // " } + } + + private void ScanRawInterpolatedStringLiteralEnd(InterpolatedStringKind kind, int startingQuoteCount) + { + Debug.Assert(kind is InterpolatedStringKind.SingleLineRaw or InterpolatedStringKind.MultiLineRaw); + + if (kind is InterpolatedStringKind.SingleLineRaw) + { + if (_lexer.TextWindow.PeekChar() != '"') + { + // Didn't find a closing quote. We hit the end of a line (in the normal case) or the end of the + // file in the normal/verbatim case. + Debug.Assert(IsAtEnd(kind)); + + TrySetError(_lexer.MakeError( + IsAtEnd(allowNewline: true) ? _lexer.TextWindow.Position - 1 : _lexer.TextWindow.Position, + width: 1, ErrorCode.ERR_UnterminatedRawString)); + } + else + { + var closeQuoteCount = _lexer.ConsumeQuoteSequence(); + + // We should only hit here if we had enough close quotes to end the string. If we didn't have + // enough they should have just have been consumed as content, and we'd hit the 'true' case in + // this 'if' instead. + // + // If we have too many close quotes for this string, report an error on the excess quotes so the + // user knows how many they need to delete. + Debug.Assert(closeQuoteCount >= startingQuoteCount); + if (closeQuoteCount > startingQuoteCount) + { + var excessQuoteCount = closeQuoteCount - startingQuoteCount; + TrySetError(_lexer.MakeError( + position: _lexer.TextWindow.Position - excessQuoteCount, + width: excessQuoteCount, + ErrorCode.ERR_TooManyQuotesForRawString)); + } + } + } + else + { + // A multiline literal might end either because: + // + // 1. we hit the end of the file. + // 2. we hit quotes *after* content on a line. + // 3. we found the legitimate end to the literal. + + if (IsAtEnd(kind)) + { + TrySetError(_lexer.MakeError( + _lexer.TextWindow.Position - 1, width: 1, ErrorCode.ERR_UnterminatedRawString)); + } + else if (_lexer.TextWindow.PeekChar() == '"') + { + // Don't allow a content line to contain a quote sequence that looks like a delimiter (or longer) + var closeQuoteCount = _lexer.ConsumeQuoteSequence(); + + // We must have too many close quotes. If we had less, they would have just been consumed as content. + Debug.Assert(closeQuoteCount >= startingQuoteCount); - closeQuoteRange = new Range(closeQuotePosition, _lexer.TextWindow.Position); + TrySetError(_lexer.MakeError( + position: _lexer.TextWindow.Position - closeQuoteCount, + width: closeQuoteCount, + ErrorCode.ERR_RawStringDelimiterOnOwnLine)); + } + else + { + _lexer.TextWindow.AdvancePastNewLine(); + _lexer.ConsumeWhitespace(builder: null); + + var closeQuoteCount = _lexer.ConsumeQuoteSequence(); + + // We should only hit here if we had enough close quotes to end the string. If we didn't have + // enough they should have just have been consumed as content, and we'd hit one of the above cases + // instead. + Debug.Assert(closeQuoteCount >= startingQuoteCount); + if (closeQuoteCount > startingQuoteCount) + { + var excessQuoteCount = closeQuoteCount - startingQuoteCount; + TrySetError(_lexer.MakeError( + position: _lexer.TextWindow.Position - excessQuoteCount, + width: excessQuoteCount, + ErrorCode.ERR_TooManyQuotesForRawString)); + } + } + } } - private void ScanInterpolatedStringLiteralContents(ArrayBuilder? interpolations) + private void ScanInterpolatedStringLiteralContents( + InterpolatedStringKind kind, int startingDollarSignCount, int startingQuoteCount, ArrayBuilder? interpolations) { + // Check for the trivial multi-line raw string literal of the form: + // + // $""" + // """ + // + // And give the special message that a content line is required in the literal. + if (CheckForIllegalEmptyMultiLineRawStringLiteral(kind, startingQuoteCount)) + return; + while (true) { - if (IsAtEnd()) + if (IsAtEnd(kind)) { - // error: end of line before end of string + // error: end of line/file before end of string pop out. Error will be reported in + // ScanInterpolatedStringLiteralEnd return; } + if (IsAtEndOfMultiLineRawLiteral(kind, startingQuoteCount)) + return; + switch (_lexer.TextWindow.PeekChar()) { case '"': - if (RecoveringFromRunawayLexing()) - { - // When recovering from mismatched delimiters, we consume the next - // quote character as the close quote for the interpolated string. In - // practice this gets us out of trouble in scenarios we've encountered. - // See, for example, https://github.com/dotnet/roslyn/issues/44789 + // Depending on the type of string or the escapes involved, this may be the end of the + // string literal, or it may just be content. + if (IsEndDelimiterOtherwiseConsume(kind, startingQuoteCount)) return; - } - if (_kind is InterpolatedStringKind.Verbatim && _lexer.TextWindow.PeekChar(1) == '"') - { - _lexer.TextWindow.AdvanceChar(2); // "" - continue; - } - // found the end of the string - return; + continue; case '}': - var pos = _lexer.TextWindow.Position; - _lexer.TextWindow.AdvanceChar(); // } - // ensure any } characters are doubled up - if (_lexer.TextWindow.PeekChar() == '}') - { - _lexer.TextWindow.AdvanceChar(); // } - } - else - { - TrySetUnrecoverableError(_lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "}")); - } + HandleCloseBraceInContent(kind, startingDollarSignCount); continue; case '{': - if (_lexer.TextWindow.PeekChar(1) == '{') - { - _lexer.TextWindow.AdvanceChar(2); // {{ - } - else - { - int openBracePosition = _lexer.TextWindow.Position; - _lexer.TextWindow.AdvanceChar(); - ScanInterpolatedStringLiteralHoleBalancedText('}', isHole: true, out var colonRange); - int closeBracePosition = _lexer.TextWindow.Position; - if (_lexer.TextWindow.PeekChar() == '}') - { - _lexer.TextWindow.AdvanceChar(); - } - else - { - TrySetUnrecoverableError(_lexer.MakeError(openBracePosition - 1, 2, ErrorCode.ERR_UnclosedExpressionHole)); - } - - interpolations?.Add(new Interpolation( - new Range(openBracePosition, openBracePosition + 1), - colonRange, - new Range(closeBracePosition, _lexer.TextWindow.Position))); - } + HandleOpenBraceInContent(kind, startingDollarSignCount, interpolations); continue; case '\\': - if (_kind is InterpolatedStringKind.Verbatim) + // In a normal interpolated string a backslash starts an escape. In all other interpolated + // strings it's just a backslash. + if (kind == InterpolatedStringKind.Normal) { - goto default; + var escapeStart = _lexer.TextWindow.Position; + char ch = _lexer.ScanEscapeSequence(surrogateCharacter: out _); + if (ch is '{' or '}') + { + TrySetError(_lexer.MakeError(escapeStart, _lexer.TextWindow.Position - escapeStart, ErrorCode.ERR_EscapedCurly, ch)); + } } - - var escapeStart = _lexer.TextWindow.Position; - char ch = _lexer.ScanEscapeSequence(surrogateCharacter: out _); - if (ch is '{' or '}') + else { - TrySetUnrecoverableError(_lexer.MakeError(escapeStart, _lexer.TextWindow.Position - escapeStart, ErrorCode.ERR_EscapedCurly, ch)); + _lexer.TextWindow.AdvanceChar(); } continue; + default: - // found some other character in the string portion + // found some other character in the string portion. Just consume it as content and continue. _lexer.TextWindow.AdvanceChar(); continue; } } } - private void ScanFormatSpecifier() + private bool CheckForIllegalEmptyMultiLineRawStringLiteral(InterpolatedStringKind kind, int startingQuoteCount) + { + if (kind == InterpolatedStringKind.MultiLineRaw) + { + _lexer.ConsumeWhitespace(builder: null); + var beforeQuotesPosition = _lexer.TextWindow.Position; + var closeQuoteCount = _lexer.ConsumeQuoteSequence(); + + if (closeQuoteCount >= startingQuoteCount) + { + // Found the end of the string. reset our position so that ScanInterpolatedStringLiteralEnd + // can consume it. + this.TrySetError(_lexer.MakeError( + _lexer.TextWindow.Position - closeQuoteCount, closeQuoteCount, ErrorCode.ERR_RawStringMustContainContent)); + _lexer.TextWindow.Reset(beforeQuotesPosition); + return true; + } + } + + return false; + } + + private bool IsAtEndOfMultiLineRawLiteral(InterpolatedStringKind kind, int startingQuoteCount) + { + if (kind == InterpolatedStringKind.MultiLineRaw) + { + // A multiline string ends with a newline, whitespace and at least as many quotes as we started with. + + var startPosition = _lexer.TextWindow.Position; + if (SyntaxFacts.IsNewLine(_lexer.TextWindow.PeekChar())) + { + _lexer.TextWindow.AdvancePastNewLine(); + _lexer.ConsumeWhitespace(builder: null); + var closeQuoteCount = _lexer.ConsumeQuoteSequence(); + + _lexer.TextWindow.Reset(startPosition); + + if (closeQuoteCount >= startingQuoteCount) + return true; + } + } + + return false; + } + + /// + /// Returns if the quote was an end delimiter and lexing of the contents of the + /// interpolated string literal should stop. If it was an end delimeter it will not be consumed. If it is + /// content and should not terminate the string then it will be consumed by this method. + /// + private bool IsEndDelimiterOtherwiseConsume(InterpolatedStringKind kind, int startingQuoteCount) + { + if (kind is InterpolatedStringKind.Normal or InterpolatedStringKind.Verbatim) + { + // When recovering from mismatched delimiters, we consume the next sequence of quote + // characters as the close quote for the interpolated string. In practice this gets us + // out of trouble in scenarios we've encountered. See, for example, + // https://github.com/dotnet/roslyn/issues/44789 + if (this.RecoveringFromRunawayLexing()) + { + return true; + } + + if (kind == InterpolatedStringKind.Normal) + { + // Was in a normal $" string, the next " closes us. + return true; + } + + Debug.Assert(kind == InterpolatedStringKind.Verbatim); + // In a verbatim string a "" sequence is an escape. Otherwise this terminates us. + if (_lexer.TextWindow.PeekChar(1) != '"') + { + return true; + } + + // Was just escaped content. Consume it. + _lexer.TextWindow.AdvanceChar(2); // "" + } + else + { + Debug.Assert(kind is InterpolatedStringKind.SingleLineRaw or InterpolatedStringKind.MultiLineRaw); + + var beforeQuotePosition = _lexer.TextWindow.Position; + var currentQuoteCount = _lexer.ConsumeQuoteSequence(); + if (currentQuoteCount >= startingQuoteCount) + { + // we saw a long enough sequence of close quotes to finish us. Move back to before the close quotes + // and let the caller handle this (including error-ing if there are too many close quotes, or if the + // close quotes are in the wrong location). + _lexer.TextWindow.Reset(beforeQuotePosition); + return true; + } + } + + // otherwise, these were just quotes that we should treat as raw content. + return false; + } + + private void HandleCloseBraceInContent(InterpolatedStringKind kind, int startingDollarSignCount) + { + if (kind is InterpolatedStringKind.Normal or InterpolatedStringKind.Verbatim) + { + var pos = _lexer.TextWindow.Position; + _lexer.TextWindow.AdvanceChar(); // } + + // ensure any } characters are doubled up + if (_lexer.TextWindow.PeekChar() == '}') + { + _lexer.TextWindow.AdvanceChar(); // } + } + else + { + TrySetError(_lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "}")); + } + } + else + { + Debug.Assert(kind is InterpolatedStringKind.MultiLineRaw or InterpolatedStringKind.SingleLineRaw); + + // A close quote is normally fine as content in a raw interpolated string literal. However, similar + // to the rules around quotes, we do not allow a subsequence of braces to be longer than the number + // of `$`s the literal starts with. Note: this restriction is only on *content*. It acceptable to + // have a sequence of braces be longer, as long as it is part content and also part of an + // interpolation. In that case, the content portion must abide by this rule. + var closeBraceCount = _lexer.ConsumeCloseBraceSequence(); + if (closeBraceCount >= startingDollarSignCount) + { + TrySetError(_lexer.MakeError( + position: _lexer.TextWindow.Position - closeBraceCount, + width: closeBraceCount, + ErrorCode.ERR_TooManyCloseBracesForRawString)); + } + } + } + + private void HandleOpenBraceInContent(InterpolatedStringKind kind, int startingDollarSignCount, ArrayBuilder? interpolations) + { + if (kind is InterpolatedStringKind.Normal or InterpolatedStringKind.Verbatim) + { + HandleOpenBraceInNormalOrVerbatimContent(kind, interpolations); + } + else + { + HandleOpenBraceInRawContent(kind, startingDollarSignCount, interpolations); + } + } + + private void HandleOpenBraceInNormalOrVerbatimContent(InterpolatedStringKind kind, ArrayBuilder? interpolations) + { + Debug.Assert(kind is InterpolatedStringKind.Normal or InterpolatedStringKind.Verbatim); + if (_lexer.TextWindow.PeekChar(1) == '{') + { + _lexer.TextWindow.AdvanceChar(2); // {{ + } + else + { + int openBracePosition = _lexer.TextWindow.Position; + _lexer.TextWindow.AdvanceChar(); + ScanInterpolatedStringLiteralHoleBalancedText(kind, '}', isHole: true, out var colonRange); + int closeBracePosition = _lexer.TextWindow.Position; + if (_lexer.TextWindow.PeekChar() == '}') + { + _lexer.TextWindow.AdvanceChar(); + } + else + { + TrySetError(_lexer.MakeError(openBracePosition - 1, 2, ErrorCode.ERR_UnclosedExpressionHole)); + } + + interpolations?.Add(new Interpolation( + new Range(openBracePosition, openBracePosition + 1), + colonRange, + new Range(closeBracePosition, _lexer.TextWindow.Position))); + } + } + + private void HandleOpenBraceInRawContent(InterpolatedStringKind kind, int startingDollarSignCount, ArrayBuilder? interpolations) + { + Debug.Assert(kind is InterpolatedStringKind.SingleLineRaw or InterpolatedStringKind.MultiLineRaw); + + // In raw content we are allowed to see up to 2*N-1 open (or close) braces. For example, if the string + // literal starts with `$$$"""` then we can see up to `2*3-1 = 5` braces like so `$$$""" {{{{{`. The + // inner three braces start the interpolation. The outer two braces are just content. This ensures the + // rule that the content cannot contain a sequence of open or close braces equal to (or longer than) the + // dollar sequence. + var beforeOpenBracesPosition = _lexer.TextWindow.Position; + var openBraceCount = _lexer.ConsumeOpenBraceSequence(); + if (openBraceCount < startingDollarSignCount) + { + // not enough open braces to matter. Just treat as content. + return; + } + + var afterOpenBracePosition = _lexer.TextWindow.Position; + if (openBraceCount >= 2 * startingDollarSignCount) + { + // Too many open braces. Report an error on the portion up before the section that counts as the + // start of the interpolation. + TrySetError(_lexer.MakeError( + beforeOpenBracesPosition, + width: openBraceCount - startingDollarSignCount, + ErrorCode.ERR_TooManyOpenBracesForRawString)); + } + + // Now, try to scan the contents of the interpolation. Ending when we hit a close brace. + ScanInterpolatedStringLiteralHoleBalancedText(kind, '}', isHole: true, out var colonRange); + + var beforeCloseBracePosition = _lexer.TextWindow.Position; + var closeBraceCount = _lexer.ConsumeCloseBraceSequence(); + + if (closeBraceCount == 0) + { + // Didn't find any close braces. Report a particular error on the open braces that they are unclosed. + TrySetError(_lexer.MakeError( + position: afterOpenBracePosition - startingDollarSignCount, + width: startingDollarSignCount, + ErrorCode.ERR_UnclosedExpressionHole)); + } + else if (closeBraceCount < startingDollarSignCount) + { + // not enough close braces to end the interpolation. Report here. + TrySetError(_lexer.MakeError( + beforeOpenBracesPosition, + width: openBraceCount - startingDollarSignCount, + ErrorCode.ERR_NotEnoughCloseBracesForRawString)); + } + else + { + // Only consume up to the minimum number of close braces we need to end the interpolation. Any + // excess will be consumed in the content consumption pass in ScanInterpolatedStringLiteralContents. + _lexer.TextWindow.Reset(beforeCloseBracePosition + startingDollarSignCount); + } + + interpolations?.Add(new Interpolation( + (afterOpenBracePosition - startingDollarSignCount)..afterOpenBracePosition, + colonRange, + beforeCloseBracePosition.._lexer.TextWindow.Position)); + } + + private void ScanFormatSpecifier(InterpolatedStringKind kind) { /* ## Grammar from spec: @@ -467,19 +919,19 @@ private void ScanFormatSpecifier() while (true) { char ch = _lexer.TextWindow.PeekChar(); - if (ch == '\\' && _kind is InterpolatedStringKind.Normal) + if (ch == '\\' && kind is InterpolatedStringKind.Normal) { // normal string & char constants can have escapes var pos = _lexer.TextWindow.Position; ch = _lexer.ScanEscapeSequence(surrogateCharacter: out _); if (ch is '{' or '}') { - TrySetUnrecoverableError(_lexer.MakeError(pos, 1, ErrorCode.ERR_EscapedCurly, ch)); + TrySetError(_lexer.MakeError(pos, 1, ErrorCode.ERR_EscapedCurly, ch)); } } else if (ch == '"') { - if (_kind is InterpolatedStringKind.Verbatim && _lexer.TextWindow.PeekChar(1) == '"') + if (kind is InterpolatedStringKind.Verbatim && _lexer.TextWindow.PeekChar(1) == '"') { _lexer.TextWindow.AdvanceChar(2); // "" } @@ -490,14 +942,15 @@ private void ScanFormatSpecifier() } else if (ch == '{') { - TrySetUnrecoverableError(_lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_UnexpectedCharacter, ch)); + TrySetError(_lexer.MakeError( + _lexer.TextWindow.Position, 1, ErrorCode.ERR_UnexpectedCharacter, ch)); _lexer.TextWindow.AdvanceChar(); } else if (ch == '}') { return; // end of interpolation } - else if (IsAtEnd()) + else if (IsAtEnd(allowNewline: true)) { return; // premature end; let caller complain } @@ -511,7 +964,7 @@ private void ScanFormatSpecifier() /// /// Scan past the hole inside an interpolated string literal, leaving the current character on the '}' (if any) /// - private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool isHole, out Range colonRange) + private void ScanInterpolatedStringLiteralHoleBalancedText(InterpolatedStringKind kind, char endingChar, bool isHole, out Range colonRange) { colonRange = default; while (true) @@ -530,7 +983,7 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool { case '#': // preprocessor directives not allowed. - TrySetUnrecoverableError(_lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString())); + TrySetError(_lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString())); _lexer.TextWindow.AdvanceChar(); continue; case '$': @@ -549,7 +1002,7 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool { Debug.Assert(colonRange.Equals(default(Range))); colonRange = new Range(_lexer.TextWindow.Position, _lexer.TextWindow.Position + 1); - ScanFormatSpecifier(); + ScanFormatSpecifier(kind); return; } @@ -562,7 +1015,7 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool return; } - TrySetUnrecoverableError(_lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString())); + TrySetError(_lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString())); goto default; case '"': if (RecoveringFromRunawayLexing()) @@ -606,15 +1059,15 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool } case '{': // TODO: after the colon this has no special meaning. - ScanInterpolatedStringLiteralHoleBracketed('{', '}'); + ScanInterpolatedStringLiteralHoleBracketed(kind, '{', '}'); continue; case '(': // TODO: after the colon this has no special meaning. - ScanInterpolatedStringLiteralHoleBracketed('(', ')'); + ScanInterpolatedStringLiteralHoleBracketed(kind, '(', ')'); continue; case '[': // TODO: after the colon this has no special meaning. - ScanInterpolatedStringLiteralHoleBracketed('[', ']'); + ScanInterpolatedStringLiteralHoleBracketed(kind, '[', ']'); continue; default: // part of code in the expression hole @@ -633,15 +1086,15 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool private void ScanInterpolatedStringLiteralNestedString() { - var discarded = default(TokenInfo); - _lexer.ScanStringLiteral(ref discarded, inDirective: false); + var info = default(TokenInfo); + _lexer.ScanStringLiteral(ref info, inDirective: false); } - private void ScanInterpolatedStringLiteralHoleBracketed(char start, char end) + private void ScanInterpolatedStringLiteralHoleBracketed(InterpolatedStringKind kind, char start, char end) { Debug.Assert(start == _lexer.TextWindow.PeekChar()); _lexer.TextWindow.AdvanceChar(); - ScanInterpolatedStringLiteralHoleBalancedText(end, isHole: false, colonRange: out _); + ScanInterpolatedStringLiteralHoleBalancedText(kind, end, isHole: false, colonRange: out _); if (_lexer.TextWindow.PeekChar() == end) { _lexer.TextWindow.AdvanceChar(); diff --git a/src/Compilers/CSharp/Portable/Parser/QuickScanner.cs b/src/Compilers/CSharp/Portable/Parser/QuickScanner.cs index 4acec774daedb..8c409c7588fa3 100644 --- a/src/Compilers/CSharp/Portable/Parser/QuickScanner.cs +++ b/src/Compilers/CSharp/Portable/Parser/QuickScanner.cs @@ -206,14 +206,14 @@ private SyntaxToken QuickScanSyntaxToken() //localize frequently accessed fields var charWindow = TextWindow.CharacterWindow; - var charPropLength = s_charProperties.Length; + var charPropLength = CharProperties.Length; for (; i < n; i++) { char c = charWindow[i]; int uc = unchecked((int)c); - var flags = uc < charPropLength ? (CharFlags)s_charProperties[uc] : CharFlags.Complex; + var flags = uc < charPropLength ? (CharFlags)CharProperties[uc] : CharFlags.Complex; state = (QuickScanState)s_stateTransitions[(int)state, (int)flags]; // NOTE: that Bad > Done and it is the only state like that @@ -273,7 +273,7 @@ private SyntaxToken CreateQuickToken() // # is marked complex as it may start directives. // PERF: Use byte instead of CharFlags so the compiler can use array literal initialization. // The most natural type choice, Enum arrays, are not blittable due to a CLR limitation. - private static readonly byte[] s_charProperties = new[] + private static ReadOnlySpan CharProperties => new[] { // 0 .. 31 (byte)CharFlags.Complex, (byte)CharFlags.Complex, (byte)CharFlags.Complex, (byte)CharFlags.Complex, (byte)CharFlags.Complex, (byte)CharFlags.Complex, (byte)CharFlags.Complex, (byte)CharFlags.Complex, diff --git a/src/Compilers/CSharp/Portable/Parser/SlidingTextWindow.cs b/src/Compilers/CSharp/Portable/Parser/SlidingTextWindow.cs index 49cfe10a8c035..be58598028b35 100644 --- a/src/Compilers/CSharp/Portable/Parser/SlidingTextWindow.cs +++ b/src/Compilers/CSharp/Portable/Parser/SlidingTextWindow.cs @@ -273,6 +273,32 @@ public void AdvanceChar(int n) _offset += n; } + /// + /// Moves past the newline that the text window is currently pointing at. The text window must be pointing at a + /// newline. If the newline is \r\n then that entire sequence will be skipped. Otherwise, the text + /// window will only advance past a single character. + /// + public void AdvancePastNewLine() + { + AdvanceChar(GetNewLineWidth()); + } + + /// + /// Gets the length of the newline the text window must be pointing at here. For \r\n this is 2, + /// for everything else, this is 1. + /// + public int GetNewLineWidth() + { + Debug.Assert(SyntaxFacts.IsNewLine(this.PeekChar())); + return GetNewLineWidth(this.PeekChar(), this.PeekChar(1)); + } + + public static int GetNewLineWidth(char currentChar, char nextChar) + { + Debug.Assert(SyntaxFacts.IsNewLine(currentChar)); + return currentChar == '\r' && nextChar == '\n' ? 2 : 1; + } + /// /// Grab the next character and advance the position. /// diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt index 4394c73ed1a6f..baa8a45fbb3d4 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Shipped.txt @@ -10,12 +10,19 @@ abstract Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax. abstract Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseArgumentListSyntax.Arguments.get -> Microsoft.CodeAnalysis.SeparatedSyntaxList abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseCrefParameterListSyntax.Parameters.get -> Microsoft.CodeAnalysis.SeparatedSyntaxList +abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax.ColonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax.Expression.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseFieldDeclarationSyntax.Declaration.get -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseFieldDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.Body.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.ParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.Externs.get -> Microsoft.CodeAnalysis.SyntaxList +abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList +abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! +abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.NamespaceKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.Usings.get -> Microsoft.CodeAnalysis.SyntaxList abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseObjectCreationExpressionSyntax.ArgumentList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax? abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseObjectCreationExpressionSyntax.Initializer.get -> Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax? abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseObjectCreationExpressionSyntax.NewKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken @@ -46,6 +53,9 @@ abstract Microsoft.CodeAnalysis.CSharp.Syntax.DirectiveTriviaSyntax.EndOfDirecti abstract Microsoft.CodeAnalysis.CSharp.Syntax.DirectiveTriviaSyntax.HashToken.get -> Microsoft.CodeAnalysis.SyntaxToken abstract Microsoft.CodeAnalysis.CSharp.Syntax.DirectiveTriviaSyntax.IsActive.get -> bool abstract Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.ArrowToken.get -> Microsoft.CodeAnalysis.SyntaxToken +abstract Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList +abstract Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken +abstract Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.LineKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken abstract Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList abstract Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList abstract Microsoft.CodeAnalysis.CSharp.Syntax.SimpleNameSyntax.Identifier.get -> Microsoft.CodeAnalysis.SyntaxToken @@ -82,11 +92,13 @@ Microsoft.CodeAnalysis.CSharp.Conversion.IsExplicit.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsIdentity.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsImplicit.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsInterpolatedString.get -> bool +Microsoft.CodeAnalysis.CSharp.Conversion.IsInterpolatedStringHandler.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsIntPtr.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsMethodGroup.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsNullable.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsNullLiteral.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsNumeric.get -> bool +Microsoft.CodeAnalysis.CSharp.Conversion.IsObjectCreation.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsPointer.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsReference.get -> bool Microsoft.CodeAnalysis.CSharp.Conversion.IsStackAlloc.get -> bool @@ -235,6 +247,7 @@ Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.IsAsynchronous.get -> bool Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.MoveNextMethod.get -> Microsoft.CodeAnalysis.IMethodSymbol? Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp1 = 1 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion +Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp10 = 1000 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp2 = 2 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp3 = 3 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp4 = 4 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion @@ -455,6 +468,9 @@ Microsoft.CodeAnalysis.CSharp.Syntax.BaseArgumentListSyntax.WithArguments(Micros Microsoft.CodeAnalysis.CSharp.Syntax.BaseCrefParameterListSyntax Microsoft.CodeAnalysis.CSharp.Syntax.BaseCrefParameterListSyntax.AddParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseCrefParameterListSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.BaseCrefParameterListSyntax.WithParameters(Microsoft.CodeAnalysis.SeparatedSyntaxList parameters) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseCrefParameterListSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax.WithColonToken(Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionSyntax.Token.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionSyntax! @@ -486,6 +502,19 @@ Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.WithExpressionB Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.WithParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddExterns(params Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddMembers(params Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddUsings(params Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithExterns(Microsoft.CodeAnalysis.SyntaxList externs) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithMembers(Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithName(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithNamespaceKeyword(Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithUsings(Microsoft.CodeAnalysis.SyntaxList usings) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.BaseObjectCreationExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.BaseObjectCreationExpressionSyntax.AddArgumentListArguments(params Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseObjectCreationExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.BaseObjectCreationExpressionSyntax.WithArgumentList(Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax? argumentList) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseObjectCreationExpressionSyntax! @@ -785,12 +814,15 @@ Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.AddBody Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.AddBodyStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.AddParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.ExplicitInterfaceSpecifier.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.ImplicitOrExplicitKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.OperatorKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.Type.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.WithBody(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.WithExplicitInterfaceSpecifier(Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.WithImplicitOrExplicitKeyword(Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! @@ -1089,6 +1121,10 @@ Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax.Name.get - Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken dotToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax.WithDotToken(Microsoft.CodeAnalysis.SyntaxToken dotToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax.WithName(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression, Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.WithColonToken(Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionOrPatternSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! @@ -1120,6 +1156,22 @@ Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.WithAttributeLists(M Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.WithDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddExterns(params Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddMembers(params Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddUsings(params Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithExterns(Microsoft.CodeAnalysis.SyntaxList externs) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithMembers(Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithName(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithNamespaceKeyword(Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithUsings(Microsoft.CodeAnalysis.SyntaxList usings) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax.AddBlockAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax.AddBlockStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! @@ -1525,11 +1577,13 @@ Microsoft.CodeAnalysis.CSharp.Syntax.LabeledStatementSyntax.WithColonToken(Micro Microsoft.CodeAnalysis.CSharp.Syntax.LabeledStatementSyntax.WithIdentifier(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.LabeledStatementSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LabeledStatementSyntax.WithStatement(Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax! statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.LabeledStatementSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.AddBlockAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.AddBlockStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.WithArrowToken(Microsoft.CodeAnalysis.SyntaxToken arrowToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax! ~Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.WithAsyncKeyword(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.WithBlock(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax! ~Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.WithBody(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode body) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax! @@ -1544,10 +1598,20 @@ Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax.WithEqualsToken(Microsoft.C Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax.WithIdentifier(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax.WithLetKeyword(Microsoft.CodeAnalysis.SyntaxToken letKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Character.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.CloseParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.CommaToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Line.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.OpenParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.SyntaxToken line, Microsoft.CodeAnalysis.SyntaxToken commaToken, Microsoft.CodeAnalysis.SyntaxToken character, Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithCharacter(Microsoft.CodeAnalysis.SyntaxToken character) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithCloseParenToken(Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithCommaToken(Microsoft.CodeAnalysis.SyntaxToken commaToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithLine(Microsoft.CodeAnalysis.SyntaxToken line) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithOpenParenToken(Microsoft.CodeAnalysis.SyntaxToken openParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.Line.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.LineKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken lineKeyword, Microsoft.CodeAnalysis.SyntaxToken line, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.WithEndOfDirectiveToken(Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.WithFile(Microsoft.CodeAnalysis.SyntaxToken file) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! @@ -1555,6 +1619,37 @@ Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.WithHashToken(Mic Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.WithIsActive(bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.WithLine(Microsoft.CodeAnalysis.SyntaxToken line) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.WithLineKeyword(Microsoft.CodeAnalysis.SyntaxToken lineKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.WithEndOfDirectiveToken(Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.WithFile(Microsoft.CodeAnalysis.SyntaxToken file) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.WithHashToken(Microsoft.CodeAnalysis.SyntaxToken hashToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.WithLineKeyword(Microsoft.CodeAnalysis.SyntaxToken lineKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.CharacterOffset.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.End.get -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.MinusToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.Start.get -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken lineKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start, Microsoft.CodeAnalysis.SyntaxToken minusToken, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end, Microsoft.CodeAnalysis.SyntaxToken characterOffset, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithCharacterOffset(Microsoft.CodeAnalysis.SyntaxToken characterOffset) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithEnd(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithEndOfDirectiveToken(Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithFile(Microsoft.CodeAnalysis.SyntaxToken file) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithHashToken(Microsoft.CodeAnalysis.SyntaxToken hashToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithIsActive(bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithLineKeyword(Microsoft.CodeAnalysis.SyntaxToken lineKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithMinusToken(Microsoft.CodeAnalysis.SyntaxToken minusToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithStart(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.AddPatterns(params Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.CloseBracketToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Designation.get -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.OpenBracketToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Patterns.get -> Microsoft.CodeAnalysis.SeparatedSyntaxList +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken openBracketToken, Microsoft.CodeAnalysis.SeparatedSyntaxList patterns, Microsoft.CodeAnalysis.SyntaxToken closeBracketToken, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.WithCloseBracketToken(Microsoft.CodeAnalysis.SyntaxToken closeBracketToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.WithDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.WithOpenBracketToken(Microsoft.CodeAnalysis.SyntaxToken openBracketToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.WithPatterns(Microsoft.CodeAnalysis.SeparatedSyntaxList patterns) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax.Token.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax! @@ -1688,7 +1783,6 @@ Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax.WithReturnType(Micr Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax.WithTypeParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.ColonToken.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.WithColonToken(Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax! @@ -1713,15 +1807,10 @@ Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.AddMembers(param Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.AddUsings(params Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.CloseBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Externs.get -> Microsoft.CodeAnalysis.SyntaxList -Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList -Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.NamespaceKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.OpenBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Usings.get -> Microsoft.CodeAnalysis.SyntaxList Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.WithCloseBraceToken(Microsoft.CodeAnalysis.SyntaxToken closeBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.WithExterns(Microsoft.CodeAnalysis.SyntaxList externs) -> Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax! @@ -1773,12 +1862,15 @@ Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.AddBodyAttributeL Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.AddBodyStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.AddParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.ExplicitInterfaceSpecifier.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.OperatorKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.OperatorToken.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.ReturnType.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.WithBody(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.WithExplicitInterfaceSpecifier(Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.WithOperatorKeyword(Microsoft.CodeAnalysis.SyntaxToken operatorKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! @@ -1820,10 +1912,13 @@ Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.Default.get -> Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax? +Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.ExclamationExclamationToken.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.Identifier.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax! default) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? type, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.SyntaxToken exclamationExclamationToken, Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax? default) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.WithDefault(Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax? default) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.WithExclamationExclamationToken(Microsoft.CodeAnalysis.SyntaxToken exclamationExclamationToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.WithIdentifier(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.WithType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? type) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! @@ -1836,21 +1931,27 @@ Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedExpressionSyntax.WithClosePare Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedExpressionSyntax.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedExpressionSyntax.WithOpenParenToken(Microsoft.CodeAnalysis.SyntaxToken openParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AddBlockAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AddBlockStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AddParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.ParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.ReturnType.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? +Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithArrowToken(Microsoft.CodeAnalysis.SyntaxToken arrowToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithAsyncKeyword(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithBlock(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithBody(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithReturnType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? returnType) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedPatternSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedPatternSyntax.CloseParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedPatternSyntax.OpenParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken @@ -2022,10 +2123,13 @@ Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.AddMembers(params M Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.AddParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.AddTypeParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.ClassOrStructKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.ParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? +Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken classOrStructKeyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithBaseList(Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithClassOrStructKeyword(Microsoft.CodeAnalysis.SyntaxToken classOrStructKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithCloseBraceToken(Microsoft.CodeAnalysis.SyntaxToken closeBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithConstraintClauses(Microsoft.CodeAnalysis.SyntaxList constraintClauses) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithIdentifier(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! @@ -2138,17 +2242,20 @@ Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax.WithType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleBaseTypeSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AddBlockAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AddBlockStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AddParameterAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AddParameterModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Parameter.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.WithArrowToken(Microsoft.CodeAnalysis.SyntaxToken arrowToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.WithAsyncKeyword(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.WithBlock(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.WithBody(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! @@ -2175,6 +2282,12 @@ Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax.AddTokens(params Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax.Tokens.get -> Microsoft.CodeAnalysis.SyntaxTokenList Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax.Update(Microsoft.CodeAnalysis.SyntaxTokenList tokens) -> Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax.WithTokens(Microsoft.CodeAnalysis.SyntaxTokenList tokens) -> Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.DotDotToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.Pattern.get -> Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? +Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken dotDotToken, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.WithDotDotToken(Microsoft.CodeAnalysis.SyntaxToken dotDotToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.WithPattern(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax.Initializer.get -> Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax? Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax.StackAllocKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken @@ -2208,9 +2321,12 @@ Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax.WithSemicolonToken( Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax.WithTypeParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.StructuredTriviaSyntax Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.ExpressionColon.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax? Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.NameColon.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax? Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.Pattern.get -> Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax? expressionColon, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax! pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax? nameColon, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax! pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.WithExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax? expressionColon) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.WithNameColon(Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax? nameColon) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.WithPattern(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax! pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax @@ -2442,12 +2558,15 @@ Microsoft.CodeAnalysis.CSharp.Syntax.UnsafeStatementSyntax.WithBlock(Microsoft.C Microsoft.CodeAnalysis.CSharp.Syntax.UnsafeStatementSyntax.WithUnsafeKeyword(Microsoft.CodeAnalysis.SyntaxToken unsafeKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.UnsafeStatementSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.Alias.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax? +Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.GlobalKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.StaticKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken globalKeyword, Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxToken staticKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax? alias, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxToken staticKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax? alias, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.UsingKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.WithAlias(Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax? alias) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.WithGlobalKeyword(Microsoft.CodeAnalysis.SyntaxToken globalKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.WithName(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.WithStaticKeyword(Microsoft.CodeAnalysis.SyntaxToken staticKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! @@ -2786,7 +2905,6 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.ConversionOperatorMemberCref = 8602 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind.CrefBracketedParameterList = 8604 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.CrefParameter = 8605 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.CrefParameterList = 8603 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -Microsoft.CodeAnalysis.CSharp.SyntaxKind.DataKeyword = 8441 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.DecimalKeyword = 8315 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.DeclarationExpression = 9040 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.DeclarationPattern = 9000 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -2848,11 +2966,13 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.EventDeclaration = 8893 -> Microsoft.Co Microsoft.CodeAnalysis.CSharp.SyntaxKind.EventFieldDeclaration = 8874 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.EventKeyword = 8358 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExclamationEqualsToken = 8267 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExclamationExclamationToken = 8285 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExclamationToken = 8194 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExclusiveOrAssignmentExpression = 8721 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExclusiveOrExpression = 8679 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExplicitInterfaceSpecifier = 8871 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExplicitKeyword = 8383 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExpressionColon = 9069 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExpressionStatement = 8797 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExternAliasDirective = 8844 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExternKeyword = 8359 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -2860,6 +2980,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.FalseKeyword = 8324 -> Microsoft.CodeAn Microsoft.CodeAnalysis.CSharp.SyntaxKind.FalseLiteralExpression = 8753 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FieldDeclaration = 8873 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FieldKeyword = 8412 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.FileScopedNamespaceDeclaration = 8845 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FinallyClause = 8829 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FinallyKeyword = 8336 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.FixedKeyword = 8351 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -2948,9 +3069,12 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.LessThanSlashToken = 8233 -> Microsoft. Microsoft.CodeAnalysis.CSharp.SyntaxKind.LessThanToken = 8215 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.LetClause = 8777 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.LetKeyword = 8426 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.LineDirectivePosition = 9070 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.LineDirectiveTrivia = 8558 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.LineKeyword = 8475 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.LineSpanDirectiveTrivia = 9071 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.List = 1 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ListPattern = 9035 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.LoadDirectiveTrivia = 8923 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.LoadKeyword = 8485 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.LocalDeclarationStatement = 8793 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -3063,6 +3187,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.RangeExpression = 8658 -> Microsoft.Cod Microsoft.CodeAnalysis.CSharp.SyntaxKind.ReadOnlyKeyword = 8348 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RecordDeclaration = 9063 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RecordKeyword = 8444 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.RecordStructDeclaration = 9068 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RecursivePattern = 9020 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ReferenceDirectiveTrivia = 8561 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ReferenceKeyword = 8481 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -3106,6 +3231,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.SkippedTokensTrivia = 8563 -> Microsoft Microsoft.CodeAnalysis.CSharp.SyntaxKind.SlashEqualsToken = 8276 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.SlashGreaterThanToken = 8232 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.SlashToken = 8221 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.SlicePattern = 9034 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.StackAllocArrayCreationExpression = 8653 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.StackAllocKeyword = 8352 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.StaticKeyword = 8347 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind @@ -3235,6 +3361,7 @@ override Microsoft.CodeAnalysis.CSharp.CSharpCompilation.GetMethodBodyDiagnostic override Microsoft.CodeAnalysis.CSharp.CSharpCompilation.GetParseDiagnostics(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray override Microsoft.CodeAnalysis.CSharp.CSharpCompilation.GetSymbolsWithName(string! name, Microsoft.CodeAnalysis.SymbolFilter filter = Microsoft.CodeAnalysis.SymbolFilter.TypeAndMember, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! override Microsoft.CodeAnalysis.CSharp.CSharpCompilation.GetSymbolsWithName(System.Func! predicate, Microsoft.CodeAnalysis.SymbolFilter filter = Microsoft.CodeAnalysis.SymbolFilter.TypeAndMember, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! +override Microsoft.CodeAnalysis.CSharp.CSharpCompilation.GetUsedAssemblyReferences(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray override Microsoft.CodeAnalysis.CSharp.CSharpCompilation.IsCaseSensitive.get -> bool override Microsoft.CodeAnalysis.CSharp.CSharpCompilation.Language.get -> string! override Microsoft.CodeAnalysis.CSharp.CSharpCompilation.ReferencedAssemblyNames.get -> System.Collections.Generic.IEnumerable! @@ -3329,9 +3456,11 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitErrorDirectiveT override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitEventDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.EventDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitEventFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.EventFieldDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExplicitInterfaceSpecifier(Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExternAliasDirective(Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFinallyClause(Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFixedStatement(Microsoft.CodeAnalysis.CSharp.Syntax.FixedStatementSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitForEachStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? @@ -3371,7 +3500,10 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitJoinClause(Micr override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitJoinIntoClause(Microsoft.CodeAnalysis.CSharp.Syntax.JoinIntoClauseSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLabeledStatement(Microsoft.CodeAnalysis.CSharp.Syntax.LabeledStatementSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLetClause(Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLineDirectivePosition(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLineDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitListPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLiteralExpression(Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLoadDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLocalDeclarationStatement(Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? @@ -3433,6 +3565,7 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSimpleLambdaExp override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSingleVariableDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSizeOfExpression(Microsoft.CodeAnalysis.CSharp.Syntax.SizeOfExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSkippedTokensTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSlicePattern(Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitStackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitStructDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSubpattern(Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? @@ -3489,6 +3622,7 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetDiagnostics(Microsoft override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetDiagnostics(Microsoft.CodeAnalysis.SyntaxToken token) -> System.Collections.Generic.IEnumerable! override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetDiagnostics(Microsoft.CodeAnalysis.SyntaxTrivia trivia) -> System.Collections.Generic.IEnumerable! override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetDiagnostics(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetLineMappings(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetLineSpan(Microsoft.CodeAnalysis.Text.TextSpan span, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FileLinePositionSpan override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetLineVisibility(int position, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.LineVisibility override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetLocation(Microsoft.CodeAnalysis.Text.TextSpan span) -> Microsoft.CodeAnalysis.Location! @@ -3757,6 +3891,10 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.EventFieldDeclarationSyntax.Modifi override Microsoft.CodeAnalysis.CSharp.Syntax.EventFieldDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken override Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.ColonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.Expression.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList @@ -3768,6 +3906,15 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.AttributeLi override Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.Declaration.get -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! override Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList override Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Externs.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList +override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! +override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.NamespaceKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Usings.get -> Microsoft.CodeAnalysis.SyntaxList override Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.FixedStatementSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void @@ -3901,11 +4048,24 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.LabeledStatementSyntax.Accept Microsoft.CodeAnalysis.SyntaxList override Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.EndOfDirectiveToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.HashToken.get -> Microsoft.CodeAnalysis.SyntaxToken override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.IsActive.get -> bool +override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.LineKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.EndOfDirectiveToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.HashToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.IsActive.get -> bool +override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.LineKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void @@ -3938,6 +4098,8 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax.ParameterL override Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken override Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.ColonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.Expression.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! override Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.NameMemberCrefSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void @@ -3945,7 +4107,12 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.NameMemberCrefSyntax.Accept void override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Externs.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList +override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! +override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.NamespaceKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Usings.get -> Microsoft.CodeAnalysis.SyntaxList override Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax.EndOfDirectiveToken.get -> Microsoft.CodeAnalysis.SyntaxToken @@ -3990,6 +4157,7 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSynta override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.ArrowToken.get -> Microsoft.CodeAnalysis.SyntaxToken override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AsyncKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Block.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList @@ -4093,6 +4261,7 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Accep override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.ArrowToken.get -> Microsoft.CodeAnalysis.SyntaxToken override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AsyncKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Block.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList @@ -4102,6 +4271,8 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.SizeOfExpressionSyntax.Accept(Micr override Microsoft.CodeAnalysis.CSharp.Syntax.SizeOfExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? override Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void @@ -4247,7 +4418,9 @@ static Microsoft.CodeAnalysis.CSharp.CSharpCompilation.CreateScriptCompilation(s static Microsoft.CodeAnalysis.CSharp.CSharpDiagnosticFormatter.Instance.get -> Microsoft.CodeAnalysis.CSharp.CSharpDiagnosticFormatter! static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.AnalyzeControlFlow(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax! firstStatement, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax! lastStatement) -> Microsoft.CodeAnalysis.ControlFlowAnalysis? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.AnalyzeControlFlow(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax! statement) -> Microsoft.CodeAnalysis.ControlFlowAnalysis? +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.AnalyzeDataFlow(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax! constructorInitializer) -> Microsoft.CodeAnalysis.DataFlowAnalysis? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.AnalyzeDataFlow(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.DataFlowAnalysis? +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.AnalyzeDataFlow(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax! primaryConstructorBaseType) -> Microsoft.CodeAnalysis.DataFlowAnalysis? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.AnalyzeDataFlow(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax! firstStatement, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax! lastStatement) -> Microsoft.CodeAnalysis.DataFlowAnalysis? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.AnalyzeDataFlow(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax! statement) -> Microsoft.CodeAnalysis.DataFlowAnalysis? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.ClassifyConversion(this Microsoft.CodeAnalysis.Compilation? compilation, Microsoft.CodeAnalysis.ITypeSymbol! source, Microsoft.CodeAnalysis.ITypeSymbol! destination) -> Microsoft.CodeAnalysis.CSharp.Conversion @@ -4273,6 +4446,7 @@ static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Mic static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.EnumMemberDeclarationSyntax! declarationSyntax, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IFieldSymbol? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.EventDeclarationSyntax! declarationSyntax, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IEventSymbol? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax! declarationSyntax, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IAliasSymbol? +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! declarationSyntax, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.INamespaceSymbol? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax! forEachStatement, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.ILocalSymbol? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.IndexerDeclarationSyntax! declarationSyntax, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IPropertySymbol? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.JoinIntoClauseSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IRangeVariableSymbol? @@ -4346,13 +4520,15 @@ static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.TryGetSpeculativeSemanticM static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.TryGetSpeculativeSemanticModelForMethodBody(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, int position, Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax! method, out Microsoft.CodeAnalysis.SemanticModel? speculativeModel) -> bool static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.VarianceKindFromToken(this Microsoft.CodeAnalysis.SyntaxToken node) -> Microsoft.CodeAnalysis.VarianceKind static Microsoft.CodeAnalysis.CSharp.CSharpFileSystemExtensions.Emit(this Microsoft.CodeAnalysis.CSharp.CSharpCompilation! compilation, string! outputPath, string? pdbPath = null, string? xmlDocumentationPath = null, string? win32ResourcesPath = null, System.Collections.Generic.IEnumerable? manifestResources = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Emit.EmitResult! +static Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.Create(params Microsoft.CodeAnalysis.IIncrementalGenerator![]! incrementalGenerators) -> Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver! static Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.Create(params Microsoft.CodeAnalysis.ISourceGenerator![]! generators) -> Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver! -static Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.Create(System.Collections.Generic.IEnumerable generators, System.Collections.Generic.IEnumerable additionalTexts = null, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions parseOptions = null, Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider optionsProvider = null) -> Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver +static Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.Create(System.Collections.Generic.IEnumerable! generators, System.Collections.Generic.IEnumerable? additionalTexts = null, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? parseOptions = null, Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider? optionsProvider = null, Microsoft.CodeAnalysis.GeneratorDriverOptions driverOptions = default(Microsoft.CodeAnalysis.GeneratorDriverOptions)) -> Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver! +static Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.Create(System.Collections.Generic.IEnumerable! generators, System.Collections.Generic.IEnumerable? additionalTexts, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? parseOptions, Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider? optionsProvider) -> Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver! static Microsoft.CodeAnalysis.CSharp.CSharpParseOptions.Default.get -> Microsoft.CodeAnalysis.CSharp.CSharpParseOptions! static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode.DeserializeFrom(System.IO.Stream! stream, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.SyntaxNode! -static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! root, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options = null, string! path = "", System.Text.Encoding? encoding = null) -> Microsoft.CodeAnalysis.SyntaxTree! -static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! root, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options, string! path, System.Text.Encoding? encoding, System.Collections.Immutable.ImmutableDictionary? diagnosticOptions) -> Microsoft.CodeAnalysis.SyntaxTree! -static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! root, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options, string! path, System.Text.Encoding? encoding, System.Collections.Immutable.ImmutableDictionary? diagnosticOptions, bool? isGeneratedCode) -> Microsoft.CodeAnalysis.SyntaxTree! +static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! root, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options = null, string? path = "", System.Text.Encoding? encoding = null) -> Microsoft.CodeAnalysis.SyntaxTree! +static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! root, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options, string? path, System.Text.Encoding? encoding, System.Collections.Immutable.ImmutableDictionary? diagnosticOptions) -> Microsoft.CodeAnalysis.SyntaxTree! +static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! root, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options, string? path, System.Text.Encoding? encoding, System.Collections.Immutable.ImmutableDictionary? diagnosticOptions, bool? isGeneratedCode) -> Microsoft.CodeAnalysis.SyntaxTree! static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(Microsoft.CodeAnalysis.Text.SourceText! text, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options = null, string! path = "", System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.SyntaxTree! static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(Microsoft.CodeAnalysis.Text.SourceText! text, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options, string! path, System.Collections.Immutable.ImmutableDictionary? diagnosticOptions, bool? isGeneratedCode, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.SyntaxTree! static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(Microsoft.CodeAnalysis.Text.SourceText! text, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? options, string! path, System.Collections.Immutable.ImmutableDictionary? diagnosticOptions, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.SyntaxTree! @@ -4531,6 +4707,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration(Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorMemberCref(Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorMemberCrefSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorMemberCref(Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterListSyntax? parameters) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorMemberCrefSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorMemberCref(Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterListSyntax? parameters) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorMemberCrefSyntax! @@ -4628,6 +4806,7 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.EventFieldDeclaration(Microso static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.EventFieldDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken eventKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.EventFieldDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExplicitInterfaceSpecifier(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExplicitInterfaceSpecifier(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken dotToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression, Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExpressionStatement(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! @@ -4638,6 +4817,9 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExternAliasDirective(string! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FinallyClause(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block = null) -> Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FinallyClause(Microsoft.CodeAnalysis.SyntaxToken finallyKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block) -> Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FixedStatement(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax! declaration, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax! statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.FixedStatementSyntax! @@ -4757,12 +4939,20 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LabeledStatement(string! iden static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LetClause(Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LetClause(Microsoft.CodeAnalysis.SyntaxToken letKeyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.SyntaxToken equalsToken, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LetClause(string! identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineDirectivePosition(Microsoft.CodeAnalysis.SyntaxToken line, Microsoft.CodeAnalysis.SyntaxToken character) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineDirectivePosition(Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.SyntaxToken line, Microsoft.CodeAnalysis.SyntaxToken commaToken, Microsoft.CodeAnalysis.SyntaxToken character, Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken lineKeyword, Microsoft.CodeAnalysis.SyntaxToken line, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken line, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken line, Microsoft.CodeAnalysis.SyntaxToken file, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineFeed.get -> Microsoft.CodeAnalysis.SyntaxTrivia +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end, Microsoft.CodeAnalysis.SyntaxToken characterOffset, Microsoft.CodeAnalysis.SyntaxToken file, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end, Microsoft.CodeAnalysis.SyntaxToken file, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineSpanDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken lineKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start, Microsoft.CodeAnalysis.SyntaxToken minusToken, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end, Microsoft.CodeAnalysis.SyntaxToken characterOffset, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.List() -> Microsoft.CodeAnalysis.SyntaxList static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.List(System.Collections.Generic.IEnumerable! nodes) -> Microsoft.CodeAnalysis.SyntaxList +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ListPattern(Microsoft.CodeAnalysis.SeparatedSyntaxList patterns = default(Microsoft.CodeAnalysis.SeparatedSyntaxList)) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ListPattern(Microsoft.CodeAnalysis.SeparatedSyntaxList patterns, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ListPattern(Microsoft.CodeAnalysis.SyntaxToken openBracketToken, Microsoft.CodeAnalysis.SeparatedSyntaxList patterns, Microsoft.CodeAnalysis.SyntaxToken closeBracketToken, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Literal(char value) -> Microsoft.CodeAnalysis.SyntaxToken static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Literal(decimal value) -> Microsoft.CodeAnalysis.SyntaxToken static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Literal(double value) -> Microsoft.CodeAnalysis.SyntaxToken @@ -4853,6 +5043,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OmittedTypeArgument() -> Micr static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OmittedTypeArgument(Microsoft.CodeAnalysis.SyntaxToken omittedTypeArgumentToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OmittedTypeArgumentSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken operatorToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorMemberCref(Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.CrefParameterListSyntax? parameters) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorMemberCrefSyntax! @@ -4863,6 +5055,7 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OrderByClause(Microsoft.CodeA static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Ordering(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.OrderingSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Ordering(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression, Microsoft.CodeAnalysis.SyntaxToken ascendingOrDescendingKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.OrderingSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Parameter(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? type, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax? default) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Parameter(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? type, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.SyntaxToken exclamationExclamationToken, Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax? default) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Parameter(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParameterList(Microsoft.CodeAnalysis.SeparatedSyntaxList parameters = default(Microsoft.CodeAnalysis.SeparatedSyntaxList)) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParameterList(Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.SeparatedSyntaxList parameters, Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! @@ -4872,6 +5065,9 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! @@ -4939,6 +5135,10 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.QueryExpression(Microsoft.Cod static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RangeExpression() -> Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RangeExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? leftOperand, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? rightOperand) -> Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RangeExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? leftOperand, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? rightOperand) -> Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken classOrStructKeyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxToken keyword, string! identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax! typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax! baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! @@ -4976,6 +5176,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleBaseType(Microsoft.Code static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! @@ -4987,6 +5189,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SizeOfExpression(Microsoft.Co static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SizeOfExpression(Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.SizeOfExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SkippedTokensTrivia() -> Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SkippedTokensTrivia(Microsoft.CodeAnalysis.SyntaxTokenList tokens) -> Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SlicePattern(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? pattern = null) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SlicePattern(Microsoft.CodeAnalysis.SyntaxToken dotDotToken, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Space.get -> Microsoft.CodeAnalysis.SyntaxTrivia static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.StackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type) -> Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.StackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax? initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax! @@ -4996,6 +5200,7 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.StructDeclaration(Microsoft.C static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.StructDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.StructDeclaration(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.StructDeclaration(string! identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Subpattern(Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax? expressionColon, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax! pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Subpattern(Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax? nameColon, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax! pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Subpattern(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax! pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SwitchExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! governingExpression) -> Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax! @@ -5074,6 +5279,7 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UnsafeStatement(Microsoft.Cod static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UnsafeStatement(Microsoft.CodeAnalysis.SyntaxToken unsafeKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block) -> Microsoft.CodeAnalysis.CSharp.Syntax.UnsafeStatementSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UsingDirective(Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax! alias, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UsingDirective(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UsingDirective(Microsoft.CodeAnalysis.SyntaxToken globalKeyword, Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxToken staticKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax? alias, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UsingDirective(Microsoft.CodeAnalysis.SyntaxToken staticKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax? alias, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UsingDirective(Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxToken staticKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax? alias, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UsingStatement(Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax! statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingStatementSyntax! @@ -5376,9 +5582,11 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitErrorDirectiveTri virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitEventDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.EventDeclarationSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitEventFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.EventFieldDeclarationSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExplicitInterfaceSpecifier(Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExternAliasDirective(Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFinallyClause(Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFixedStatement(Microsoft.CodeAnalysis.CSharp.Syntax.FixedStatementSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitForEachStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax! node) -> void @@ -5418,7 +5626,10 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitJoinClause(Micros virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitJoinIntoClause(Microsoft.CodeAnalysis.CSharp.Syntax.JoinIntoClauseSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLabeledStatement(Microsoft.CodeAnalysis.CSharp.Syntax.LabeledStatementSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLetClause(Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineDirectivePosition(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitListPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLiteralExpression(Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLoadDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLocalDeclarationStatement(Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax! node) -> void @@ -5480,6 +5691,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSimpleLambdaExpre virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSingleVariableDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSizeOfExpression(Microsoft.CodeAnalysis.CSharp.Syntax.SizeOfExpressionSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSkippedTokensTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSlicePattern(Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitStackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitStructDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSubpattern(Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! node) -> void @@ -5609,9 +5821,11 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitErrorDir virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitEventDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.EventDeclarationSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitEventFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.EventFieldDeclarationSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExplicitInterfaceSpecifier(Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! node) -> TResult? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExternAliasDirective(Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax! node) -> TResult? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFinallyClause(Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFixedStatement(Microsoft.CodeAnalysis.CSharp.Syntax.FixedStatementSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitForEachStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax! node) -> TResult? @@ -5651,7 +5865,10 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitJoinClau virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitJoinIntoClause(Microsoft.CodeAnalysis.CSharp.Syntax.JoinIntoClauseSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLabeledStatement(Microsoft.CodeAnalysis.CSharp.Syntax.LabeledStatementSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLetClause(Microsoft.CodeAnalysis.CSharp.Syntax.LetClauseSyntax! node) -> TResult? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineDirectivePosition(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax! node) -> TResult? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! node) -> TResult? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitListPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLiteralExpression(Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLoadDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLocalDeclarationStatement(Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax! node) -> TResult? @@ -5713,6 +5930,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSimpleLa virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSingleVariableDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSizeOfExpression(Microsoft.CodeAnalysis.CSharp.Syntax.SizeOfExpressionSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSkippedTokensTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.SkippedTokensTriviaSyntax! node) -> TResult? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSlicePattern(Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitStackAllocArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.StackAllocArrayCreationExpressionSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitStructDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSubpattern(Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! node) -> TResult? diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 9d97862620003..bcce58b4b18e9 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -1,239 +1,31 @@ -Microsoft.CodeAnalysis.CSharp.Conversion.IsInterpolatedStringHandler.get -> bool -abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax.ColonToken.get -> Microsoft.CodeAnalysis.SyntaxToken -abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax.Expression.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! -abstract Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken -abstract Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.LineKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Conversion.IsObjectCreation.get -> bool -Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp10 = 1000 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion -Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax.WithColonToken(Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression, Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.WithColonToken(Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Character.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.CloseParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.CommaToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Line.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.OpenParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.SyntaxToken line, Microsoft.CodeAnalysis.SyntaxToken commaToken, Microsoft.CodeAnalysis.SyntaxToken character, Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithCharacter(Microsoft.CodeAnalysis.SyntaxToken character) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithCloseParenToken(Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithCommaToken(Microsoft.CodeAnalysis.SyntaxToken commaToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithLine(Microsoft.CodeAnalysis.SyntaxToken line) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.WithOpenParenToken(Microsoft.CodeAnalysis.SyntaxToken openParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.ExclamationExclamationToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? type, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.SyntaxToken exclamationExclamationToken, Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax? default) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax.WithExclamationExclamationToken(Microsoft.CodeAnalysis.SyntaxToken exclamationExclamationToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! -Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExclamationExclamationToken = 8285 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.AddPatterns(params Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.CloseBracketToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Designation.get -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.OpenBracketToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Patterns.get -> Microsoft.CodeAnalysis.SeparatedSyntaxList -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken openBracketToken, Microsoft.CodeAnalysis.SeparatedSyntaxList patterns, Microsoft.CodeAnalysis.SyntaxToken closeBracketToken, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.WithCloseBracketToken(Microsoft.CodeAnalysis.SyntaxToken closeBracketToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.WithDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.WithOpenBracketToken(Microsoft.CodeAnalysis.SyntaxToken openBracketToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.WithPatterns(Microsoft.CodeAnalysis.SeparatedSyntaxList patterns) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.DotDotToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.Pattern.get -> Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? -Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken dotDotToken, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.WithDotDotToken(Microsoft.CodeAnalysis.SyntaxToken dotDotToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.WithPattern(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! -Microsoft.CodeAnalysis.CSharp.SyntaxKind.ListPattern = 9035 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -Microsoft.CodeAnalysis.CSharp.SyntaxKind.SlicePattern = 9034 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitListPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSlicePattern(Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? -override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken -*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.LineKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectiveTriviaSyntax.LineKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.WithEndOfDirectiveToken(Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.WithFile(Microsoft.CodeAnalysis.SyntaxToken file) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.WithHashToken(Microsoft.CodeAnalysis.SyntaxToken hashToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax.WithLineKeyword(Microsoft.CodeAnalysis.SyntaxToken lineKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineOrSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.CharacterOffset.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.End.get -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.MinusToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.Start.get -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken lineKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start, Microsoft.CodeAnalysis.SyntaxToken minusToken, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end, Microsoft.CodeAnalysis.SyntaxToken characterOffset, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithCharacterOffset(Microsoft.CodeAnalysis.SyntaxToken characterOffset) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithEnd(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithEndOfDirectiveToken(Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithFile(Microsoft.CodeAnalysis.SyntaxToken file) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithHashToken(Microsoft.CodeAnalysis.SyntaxToken hashToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithIsActive(bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithLineKeyword(Microsoft.CodeAnalysis.SyntaxToken lineKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithMinusToken(Microsoft.CodeAnalysis.SyntaxToken minusToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.WithStart(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.ExpressionColon.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax? -Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax? expressionColon, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax! pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax.WithExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax? expressionColon) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! -Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExpressionColon = 9069 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -Microsoft.CodeAnalysis.CSharp.SyntaxKind.LineDirectivePosition = 9070 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -Microsoft.CodeAnalysis.CSharp.SyntaxKind.LineSpanDirectiveTrivia = 9071 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.InterpolatedMultiLineRawStringStartToken = 9081 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.InterpolatedRawStringEndToken = 9082 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.InterpolatedSingleLineRawStringStartToken = 9080 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.MultiLineRawStringLiteralToken = 9073 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RequiredKeyword = 8447 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Externs.get -> Microsoft.CodeAnalysis.SyntaxList -*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList -*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax -*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.NamespaceKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Usings.get -> Microsoft.CodeAnalysis.SyntaxList -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddExterns(params Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddMembers(params Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.AddUsings(params Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithExterns(Microsoft.CodeAnalysis.SyntaxList externs) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithMembers(Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithName(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithNamespaceKeyword(Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.WithUsings(Microsoft.CodeAnalysis.SyntaxList usings) -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddExterns(params Microsoft.CodeAnalysis.CSharp.Syntax.ExternAliasDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddMembers(params Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AddUsings(params Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithExterns(Microsoft.CodeAnalysis.SyntaxList externs) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithMembers(Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithName(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithNamespaceKeyword(Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.WithUsings(Microsoft.CodeAnalysis.SyntaxList usings) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.SyntaxKind.FileScopedNamespaceDeclaration = 8845 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.Externs.get -> Microsoft.CodeAnalysis.SyntaxList -abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList -abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! -abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.NamespaceKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax.Usings.get -> Microsoft.CodeAnalysis.SyntaxList -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? -override Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? -override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Externs.get -> Microsoft.CodeAnalysis.SyntaxList -override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList -override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! -override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.NamespaceKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax.Usings.get -> Microsoft.CodeAnalysis.SyntaxList -override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? -override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList -override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Externs.get -> Microsoft.CodeAnalysis.SyntaxList -override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList -override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList -override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! -override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.NamespaceKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax.Usings.get -> Microsoft.CodeAnalysis.SyntaxList -static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.AnalyzeDataFlow(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax! constructorInitializer) -> Microsoft.CodeAnalysis.DataFlowAnalysis? -static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.AnalyzeDataFlow(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax! primaryConstructorBaseType) -> Microsoft.CodeAnalysis.DataFlowAnalysis? -override Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? -static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! declarationSyntax, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.INamespaceSymbol? -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken namespaceKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken, Microsoft.CodeAnalysis.SyntaxList externs, Microsoft.CodeAnalysis.SyntaxList usings, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Parameter(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? type, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.SyntaxToken exclamationExclamationToken, Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax? default) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ListPattern(Microsoft.CodeAnalysis.SeparatedSyntaxList patterns = default(Microsoft.CodeAnalysis.SeparatedSyntaxList)) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ListPattern(Microsoft.CodeAnalysis.SeparatedSyntaxList patterns, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ListPattern(Microsoft.CodeAnalysis.SyntaxToken openBracketToken, Microsoft.CodeAnalysis.SeparatedSyntaxList patterns, Microsoft.CodeAnalysis.SyntaxToken closeBracketToken, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax? designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SlicePattern(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? pattern = null) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SlicePattern(Microsoft.CodeAnalysis.SyntaxToken dotDotToken, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax? pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! node) -> void -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitListPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! node) -> void -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSlicePattern(Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! node) -> void -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.FileScopedNamespaceDeclarationSyntax! node) -> TResult? -Microsoft.CodeAnalysis.CSharp.SyntaxKind.RecordStructDeclaration = 9068 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -override Microsoft.CodeAnalysis.CSharp.CSharpCompilation.GetUsedAssemblyReferences(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLineDirectivePosition(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? -override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? -override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.ColonToken.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax.Expression.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! -override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? -override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void -override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? -override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.EndOfDirectiveToken.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.HashToken.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.IsActive.get -> bool -override Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax.LineKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.Expression.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! -*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.ColonToken.get -> Microsoft.CodeAnalysis.SyntaxToken -override Microsoft.CodeAnalysis.CSharp.Syntax.NameColonSyntax.ColonToken.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax! -abstract Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList -Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! -override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList -Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.ReturnType.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? -Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! -*REMOVED*static Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.Create(System.Collections.Generic.IEnumerable generators, System.Collections.Generic.IEnumerable additionalTexts = null, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions parseOptions = null, Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider optionsProvider = null) -> Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver -static Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.Create(System.Collections.Generic.IEnumerable! generators, System.Collections.Generic.IEnumerable? additionalTexts = null, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? parseOptions = null, Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider? optionsProvider = null, Microsoft.CodeAnalysis.GeneratorDriverOptions driverOptions = default(Microsoft.CodeAnalysis.GeneratorDriverOptions)) -> Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver! -static Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.Create(System.Collections.Generic.IEnumerable! generators, System.Collections.Generic.IEnumerable? additionalTexts, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions? parseOptions, Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider? optionsProvider) -> Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax! expression, Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineDirectivePosition(Microsoft.CodeAnalysis.SyntaxToken line, Microsoft.CodeAnalysis.SyntaxToken character) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineDirectivePosition(Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.SyntaxToken line, Microsoft.CodeAnalysis.SyntaxToken commaToken, Microsoft.CodeAnalysis.SyntaxToken character, Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineSpanDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken lineKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start, Microsoft.CodeAnalysis.SyntaxToken minusToken, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end, Microsoft.CodeAnalysis.SyntaxToken characterOffset, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end, Microsoft.CodeAnalysis.SyntaxToken characterOffset, Microsoft.CodeAnalysis.SyntaxToken file, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! start, Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! end, Microsoft.CodeAnalysis.SyntaxToken file, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithReturnType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? returnType) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax? returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.WithClassOrStructKeyword(Microsoft.CodeAnalysis.SyntaxToken classOrStructKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken classOrStructKeyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken classOrStructKeyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax.ClassOrStructKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RecordDeclaration(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxToken keyword, string! identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.RecordDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! -override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList -Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax! parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Subpattern(Microsoft.CodeAnalysis.CSharp.Syntax.BaseExpressionColonSyntax? expressionColon, Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax! pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UsingDirective(Microsoft.CodeAnalysis.SyntaxToken globalKeyword, Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxToken staticKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax? alias, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.GlobalKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken -Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken globalKeyword, Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxToken staticKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.NameEqualsSyntax? alias, Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax! name, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax.WithGlobalKeyword(Microsoft.CodeAnalysis.SyntaxToken globalKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax! -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! node) -> void -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineDirectivePosition(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! node) -> void -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! node) -> void -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExpressionColon(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionColonSyntax! node) -> TResult? -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineDirectivePosition(Microsoft.CodeAnalysis.CSharp.Syntax.LineDirectivePositionSyntax! node) -> TResult? -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLineSpanDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LineSpanDirectiveTriviaSyntax! node) -> TResult? -*REMOVED*Microsoft.CodeAnalysis.CSharp.SyntaxKind.DataKeyword = 8441 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind -override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.GetLineMappings(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.ExplicitInterfaceSpecifier.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? -Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax.WithExplicitInterfaceSpecifier(Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.ExplicitInterfaceSpecifier.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? -Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! -Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax.WithExplicitInterfaceSpecifier(Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! -static Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver.Create(params Microsoft.CodeAnalysis.IIncrementalGenerator![]! incrementalGenerators) -> Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver! -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitListPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ListPatternSyntax! node) -> TResult? -virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSlicePattern(Microsoft.CodeAnalysis.CSharp.Syntax.SlicePatternSyntax! node) -> TResult? +Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleLineRawStringLiteralToken = 9072 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax? initializer, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax! initializer, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax? initializer, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax! initializer, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConversionOperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken implicitOrExplicitKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConversionOperatorDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DestructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken tildeToken, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DestructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken tildeToken, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.EnumMemberDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax? equalsValue) -> Microsoft.CodeAnalysis.CSharp.Syntax.EnumMemberDeclarationSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.EnumMemberDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax! equalsValue) -> Microsoft.CodeAnalysis.CSharp.Syntax.EnumMemberDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IndexerDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.CSharp.Syntax.BracketedParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.AccessorListSyntax? accessorList) -> Microsoft.CodeAnalysis.CSharp.Syntax.IndexerDeclarationSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IndexerDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! explicitInterfaceSpecifier, Microsoft.CodeAnalysis.CSharp.Syntax.BracketedParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.AccessorListSyntax! accessorList) -> Microsoft.CodeAnalysis.CSharp.Syntax.IndexerDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LocalFunctionStatement(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalFunctionStatementSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LocalFunctionStatement(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax! typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax! expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalFunctionStatementSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LocalFunctionStatement(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax? expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalFunctionStatementSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LocalFunctionStatement(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax! typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body, Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax! expressionBody, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalFunctionStatementSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax? body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.OperatorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! returnType, Microsoft.CodeAnalysis.SyntaxToken operatorKeyword, Microsoft.CodeAnalysis.SyntaxToken operatorToken, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.PropertyDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.AccessorListSyntax! accessorList) -> Microsoft.CodeAnalysis.CSharp.Syntax.PropertyDeclarationSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.PropertyDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax! type, Microsoft.CodeAnalysis.CSharp.Syntax.ExplicitInterfaceSpecifierSyntax! explicitInterfaceSpecifier, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.AccessorListSyntax! accessorList) -> Microsoft.CodeAnalysis.CSharp.Syntax.PropertyDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block, Microsoft.CodeAnalysis.SyntaxList catches, Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax? finally) -> Microsoft.CodeAnalysis.CSharp.Syntax.TryStatementSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block, Microsoft.CodeAnalysis.SyntaxList catches, Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! finally) -> Microsoft.CodeAnalysis.CSharp.Syntax.TryStatementSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAnalysis.SyntaxToken tryKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block, Microsoft.CodeAnalysis.SyntaxList catches, Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax? finally) -> Microsoft.CodeAnalysis.CSharp.Syntax.TryStatementSyntax! +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAnalysis.SyntaxToken tryKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block, Microsoft.CodeAnalysis.SyntaxList catches, Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! finally) -> Microsoft.CodeAnalysis.CSharp.Syntax.TryStatementSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.InterpolatedStringExpression(Microsoft.CodeAnalysis.SyntaxToken stringStartToken, Microsoft.CodeAnalysis.SyntaxToken stringEndToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.InterpolatedStringExpressionSyntax! diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs index d351d8a1ffb3b..777fac21badf9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Emit; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -33,26 +34,26 @@ internal sealed partial class AnonymousTypeManager /// Maps delegate signature shape (number of parameters and their ref-ness) to a synthesized generic delegate symbol. /// Currently used for dynamic call-sites and inferred delegate types whose signature doesn't match any of the well-known Func or Action types. /// - private ConcurrentDictionary _lazySynthesizedDelegates; + private ConcurrentDictionary _lazyAnonymousDelegates; - private struct SynthesizedDelegateKey : IEquatable + private readonly struct SynthesizedDelegateKey : IEquatable { - private readonly RefKindVector _byRefs; - private readonly ushort _parameterCount; - private readonly bool _returnsVoid; - private readonly int _generation; + internal readonly string Name; + internal readonly int ParameterCount; + internal readonly AnonymousTypeDescriptor TypeDescriptor; public SynthesizedDelegateKey(int parameterCount, RefKindVector byRefs, bool returnsVoid, int generation) { - _parameterCount = (ushort)parameterCount; - _returnsVoid = returnsVoid; - _generation = generation; - _byRefs = byRefs; + Name = GeneratedNames.MakeSynthesizedDelegateName(byRefs, returnsVoid, generation); + ParameterCount = parameterCount; + TypeDescriptor = default; } - public string MakeTypeName() + public SynthesizedDelegateKey(AnonymousTypeDescriptor typeDescr) { - return GeneratedNames.MakeSynthesizedDelegateName(_byRefs, _returnsVoid, _generation); + Name = null; + ParameterCount = -1; + TypeDescriptor = typeDescr; } public override bool Equals(object obj) @@ -62,32 +63,24 @@ public override bool Equals(object obj) public bool Equals(SynthesizedDelegateKey other) { - return _parameterCount == other._parameterCount - && _returnsVoid == other._returnsVoid - && _generation == other._generation - && _byRefs.Equals(other._byRefs); + if (!string.Equals(Name, other.Name)) + { + return false; + } + if (Name is null) + { + return TypeDescriptor.Equals(other.TypeDescriptor); + } + return ParameterCount == other.ParameterCount; } public override int GetHashCode() { - return Hash.Combine( - Hash.Combine((int)_parameterCount, _generation), - Hash.Combine(_returnsVoid.GetHashCode(), _byRefs.GetHashCode())); - } - } - - private struct SynthesizedDelegateValue - { - public readonly SynthesizedDelegateSymbol Delegate; - - // the manager that created this delegate: - public readonly AnonymousTypeManager Manager; - - public SynthesizedDelegateValue(AnonymousTypeManager manager, SynthesizedDelegateSymbol @delegate) - { - Debug.Assert(manager != null && (object)@delegate != null); - this.Manager = manager; - this.Delegate = @delegate; + if (Name is null) + { + return TypeDescriptor.GetHashCode(); + } + return Hash.Combine((int)ParameterCount, Name.GetHashCode()); } } @@ -140,52 +133,52 @@ private ConcurrentDictionary AnonymousTypeT } } - private ConcurrentDictionary SynthesizedDelegates + private ConcurrentDictionary AnonymousDelegates { get { - if (_lazySynthesizedDelegates == null) + if (_lazyAnonymousDelegates == null) { CSharpCompilation previousSubmission = this.Compilation.PreviousSubmission; // TODO (tomat): avoid recursion - var previousCache = (previousSubmission == null) ? null : previousSubmission.AnonymousTypeManager._lazySynthesizedDelegates; + var previousCache = (previousSubmission == null) ? null : previousSubmission.AnonymousTypeManager._lazyAnonymousDelegates; - Interlocked.CompareExchange(ref _lazySynthesizedDelegates, + Interlocked.CompareExchange(ref _lazyAnonymousDelegates, previousCache == null - ? new ConcurrentDictionary() - : new ConcurrentDictionary(previousCache), + ? new ConcurrentDictionary() + : new ConcurrentDictionary(previousCache), null); } - return _lazySynthesizedDelegates; + return _lazyAnonymousDelegates; } } #nullable enable - internal SynthesizedDelegateSymbol SynthesizeDelegate(int parameterCount, RefKindVector refKinds, bool returnsVoid, int generation) + internal AnonymousDelegateTemplateSymbol SynthesizeDelegate(int parameterCount, RefKindVector refKinds, bool returnsVoid, int generation) { // parameterCount doesn't include return type Debug.Assert(refKinds.IsNull || parameterCount == refKinds.Capacity - (returnsVoid ? 0 : 1)); var key = new SynthesizedDelegateKey(parameterCount, refKinds, returnsVoid, generation); - SynthesizedDelegateValue result; - if (this.SynthesizedDelegates.TryGetValue(key, out result)) + AnonymousDelegateTemplateSymbol? synthesizedDelegate; + if (this.AnonymousDelegates.TryGetValue(key, out synthesizedDelegate)) { - return result.Delegate; + return synthesizedDelegate; } // NOTE: the newly created template may be thrown away if another thread wins - var synthesizedDelegate = new SynthesizedDelegateSymbol( - this.Compilation.Assembly.GlobalNamespace, - key.MakeTypeName(), + synthesizedDelegate = new AnonymousDelegateTemplateSymbol( + this, + key.Name, this.System_Object, Compilation.GetSpecialType(SpecialType.System_IntPtr), returnsVoid ? Compilation.GetSpecialType(SpecialType.System_Void) : null, parameterCount, refKinds); - return this.SynthesizedDelegates.GetOrAdd(key, new SynthesizedDelegateValue(this, synthesizedDelegate)).Delegate; + return this.AnonymousDelegates.GetOrAdd(key, synthesizedDelegate); } private NamedTypeSymbol ConstructAnonymousDelegateImplementationSymbol(AnonymousDelegatePublicSymbol anonymous, int generation) @@ -193,30 +186,160 @@ private NamedTypeSymbol ConstructAnonymousDelegateImplementationSymbol(Anonymous var typeDescr = anonymous.TypeDescriptor; Debug.Assert(typeDescr.Location.IsInSource); // AnonymousDelegateTemplateSymbol requires a location in source for ordering. - var fields = typeDescr.Fields; - bool returnsVoid = fields.Last().Type.IsVoidType(); - int nTypeArguments = fields.Length - (returnsVoid ? 1 : 0); - var refKinds = default(RefKindVector); - if (fields.Any(f => f.RefKind != RefKind.None)) + // If all parameter types and return type are valid type arguments, construct + // the delegate type from a generic template. Otherwise, use a non-generic template. + if (allValidTypeArguments(typeDescr)) { - refKinds = RefKindVector.Create(nTypeArguments); + var fields = typeDescr.Fields; + bool returnsVoid = fields.Last().Type.IsVoidType(); + int nTypeArguments = fields.Length - (returnsVoid ? 1 : 0); + var refKinds = default(RefKindVector); + if (fields.Any(f => f.RefKind != RefKind.None)) + { + refKinds = RefKindVector.Create(nTypeArguments); + for (int i = 0; i < nTypeArguments; i++) + { + refKinds[i] = fields[i].RefKind; + } + } + var typeArgumentsBuilder = ArrayBuilder.GetInstance(nTypeArguments); for (int i = 0; i < nTypeArguments; i++) { - refKinds[i] = fields[i].RefKind; + typeArgumentsBuilder.Add(fields[i].TypeWithAnnotations); + } + var typeArguments = typeArgumentsBuilder.ToImmutableAndFree(); + var template = SynthesizeDelegate(parameterCount: fields.Length - 1, refKinds, returnsVoid, generation); + + Debug.Assert(typeArguments.Length == template.TypeParameters.Length); + return typeArguments.Length == 0 ? + template : + template.Construct(typeArguments); + } + else + { + var typeParameters = GetReferencedTypeParameters(typeDescr); + var key = getTemplateKey(typeDescr, typeParameters); + + // Get anonymous delegate template + AnonymousDelegateTemplateSymbol? template; + if (!this.AnonymousDelegates.TryGetValue(key, out template)) + { + template = this.AnonymousDelegates.GetOrAdd(key, new AnonymousDelegateTemplateSymbol(this, typeDescr, typeParameters)); + } + + // Adjust template location if the template is owned by this manager + if (ReferenceEquals(template.Manager, this)) + { + template.AdjustLocation(typeDescr.Location); } + + Debug.Assert(typeParameters.Length == template.TypeParameters.Length); + return typeParameters.Length == 0 ? + template : + template.Construct(typeParameters); + } + + static bool allValidTypeArguments(AnonymousTypeDescriptor typeDescr) + { + var fields = typeDescr.Fields; + int n = fields.Length; + for (int i = 0; i < n - 1; i++) + { + if (!isValidTypeArgument(fields[i])) + { + return false; + } + } + var returnParameter = fields[n - 1]; + return returnParameter.Type.IsVoidType() || isValidTypeArgument(returnParameter); + } + + static bool isValidTypeArgument(AnonymousTypeField field) + { + return field.Type is { } type && + !type.IsPointerOrFunctionPointer() && + !type.IsRestrictedType(); + } + + static SynthesizedDelegateKey getTemplateKey(AnonymousTypeDescriptor typeDescr, ImmutableArray typeParameters) + { + if (typeParameters.Length > 0) + { + var typeMap = new TypeMap(typeParameters, IndexedTypeParameterSymbol.Take(typeParameters.Length), allowAlpha: true); + typeDescr = typeDescr.SubstituteTypes(typeMap, out bool changed); + Debug.Assert(changed); + } + return new SynthesizedDelegateKey(typeDescr); + } + } + + private static ImmutableArray GetReferencedTypeParameters(AnonymousTypeDescriptor typeDescr) + { + var referenced = PooledHashSet.GetInstance(); + foreach (var field in typeDescr.Fields) + { + field.TypeWithAnnotations.VisitType( + type: null, + typeWithAnnotationsPredicate: null, + typePredicate: static (type, referenced, _) => + { + if (type is TypeParameterSymbol typeParameter) + { + referenced.Add(typeParameter); + } + return false; + }, + arg: referenced, + visitCustomModifiers: true); + } + + ImmutableArray typeParameters; + if (referenced.Count == 0) + { + typeParameters = ImmutableArray.Empty; + } + else + { + var builder = ArrayBuilder.GetInstance(); + builder.AddRange(referenced); + builder.Sort((x, y) => compareTypeParameters(x, y)); + typeParameters = builder.ToImmutableAndFree(); } - var typeArgumentsBuilder = ArrayBuilder.GetInstance(nTypeArguments); - for (int i = 0; i < nTypeArguments; i++) + referenced.Free(); + return typeParameters; + + static int compareTypeParameters(TypeParameterSymbol x, TypeParameterSymbol y) { - typeArgumentsBuilder.Add(fields[i].TypeWithAnnotations); + var xOwner = x.ContainingSymbol; + var yOwner = y.ContainingSymbol; + if (xOwner.Equals(yOwner)) + { + return x.Ordinal - y.Ordinal; + } + else if (isContainedIn(xOwner, yOwner)) + { + return 1; + } + else + { + Debug.Assert(isContainedIn(yOwner, xOwner)); + return -1; + } } - var typeArguments = typeArgumentsBuilder.ToImmutableAndFree(); - var template = SynthesizeDelegate(parameterCount: fields.Length - 1, refKinds, returnsVoid, generation); - Debug.Assert(typeArguments.Length == template.TypeParameters.Length); - return typeArguments.Length == 0 ? - template : - template.Construct(typeArguments); + static bool isContainedIn(Symbol symbol, Symbol container) + { + var other = symbol.ContainingSymbol; + while (other is { }) + { + if (other.Equals(container)) + { + return true; + } + other = other.ContainingSymbol; + } + return false; + } } /// @@ -267,17 +390,16 @@ private AnonymousTypeTemplateSymbol CreatePlaceholderTemplate(Microsoft.CodeAnal return new AnonymousTypeTemplateSymbol(this, typeDescr); } - private SynthesizedDelegateValue CreatePlaceholderSynthesizedDelegateValue(string name, RefKindVector refKinds, bool returnsVoid, int parameterCount) + private AnonymousDelegateTemplateSymbol CreatePlaceholderSynthesizedDelegateValue(string name, RefKindVector refKinds, bool returnsVoid, int parameterCount) { - var symbol = new SynthesizedDelegateSymbol( - this.Compilation.Assembly.GlobalNamespace, + return new AnonymousDelegateTemplateSymbol( + this, MetadataHelpers.InferTypeArityAndUnmangleMetadataName(name, out _), this.System_Object, Compilation.GetSpecialType(SpecialType.System_IntPtr), returnsVoid ? Compilation.GetSpecialType(SpecialType.System_Void) : null, parameterCount, refKinds); - return new SynthesizedDelegateValue(this, symbol); } /// @@ -290,13 +412,16 @@ public void AssignTemplatesNamesAndCompile(MethodCompiler compiler, PEModuleBuil // types are available for subsequent edit and continue generations. foreach (var key in moduleBeingBuilt.GetPreviousAnonymousTypes()) { + Debug.Assert(!key.IsDelegate); var templateKey = AnonymousTypeDescriptor.ComputeKey(key.Fields, f => f.Name); this.AnonymousTypeTemplates.GetOrAdd(templateKey, k => this.CreatePlaceholderTemplate(key)); } // Get all anonymous types owned by this manager - var builder = ArrayBuilder.GetInstance(); - GetCreatedAnonymousTypeTemplates(builder); + var anonymousTypes = ArrayBuilder.GetInstance(); + var anonymousDelegatesWithFixedTypes = ArrayBuilder.GetInstance(); + GetCreatedAnonymousTypeTemplates(anonymousTypes); + GetCreatedAnonymousDelegatesWithFixedTypes(anonymousDelegatesWithFixedTypes); // If the collection is not sealed yet we should assign // new indexes to the created anonymous type templates @@ -324,15 +449,17 @@ public void AssignTemplatesNamesAndCompile(MethodCompiler compiler, PEModuleBuil moduleId = string.Empty; } - int nextIndex = moduleBeingBuilt.GetNextAnonymousTypeIndex(); - foreach (var template in builder) + int submissionSlotIndex = this.Compilation.GetSubmissionSlotIndex(); + + int typeIndex = moduleBeingBuilt.GetNextAnonymousTypeIndex(); + foreach (var template in anonymousTypes) { string name; int index; if (!moduleBeingBuilt.TryGetAnonymousTypeName(template, out name, out index)) { - index = nextIndex++; - name = GeneratedNames.MakeAnonymousTypeTemplateName(index, this.Compilation.GetSubmissionSlotIndex(), moduleId); + index = typeIndex++; + name = GeneratedNames.MakeAnonymousTypeOrDelegateTemplateName(index, submissionSlotIndex, moduleId, isDelegate: false); } // normally it should only happen once, but in case there is a race // NameAndIndex.set has an assert which guarantees that the @@ -340,47 +467,60 @@ public void AssignTemplatesNamesAndCompile(MethodCompiler compiler, PEModuleBuil template.NameAndIndex = new NameAndIndex(name, index); } + int delegateIndex = 0; + foreach (var template in anonymousDelegatesWithFixedTypes) + { + int index = delegateIndex++; + string name = GeneratedNames.MakeAnonymousTypeOrDelegateTemplateName(index, submissionSlotIndex, moduleId, isDelegate: true); + template.NameAndIndex = new NameAndIndex(name, index); + } + this.SealTemplates(); } - if (builder.Count > 0 && !ReportMissingOrErroneousSymbols(diagnostics)) + if (anonymousTypes.Count > 0 && !ReportMissingOrErroneousSymbols(diagnostics)) { // Process all the templates - foreach (var template in builder) + foreach (var template in anonymousTypes) { foreach (var method in template.SpecialMembers) { moduleBeingBuilt.AddSynthesizedDefinition(template, method.GetCciAdapter()); } - compiler.Visit(template, null); } } - builder.Free(); + anonymousTypes.Free(); // Ensure all previous synthesized delegates are included so the // types are available for subsequent edit and continue generations. - foreach (var key in moduleBeingBuilt.GetPreviousSynthesizedDelegates()) + foreach (var key in moduleBeingBuilt.GetPreviousAnonymousDelegates()) { if (GeneratedNames.TryParseSynthesizedDelegateName(key.Name, out var refKinds, out var returnsVoid, out var generation, out var parameterCount)) { var delegateKey = new SynthesizedDelegateKey(parameterCount, refKinds, returnsVoid, generation); - this.SynthesizedDelegates.GetOrAdd(delegateKey, (k, args) => CreatePlaceholderSynthesizedDelegateValue(key.Name, args.refKinds, args.returnsVoid, args.parameterCount), (refKinds, returnsVoid, parameterCount)); + this.AnonymousDelegates.GetOrAdd(delegateKey, (k, args) => CreatePlaceholderSynthesizedDelegateValue(key.Name, args.refKinds, args.returnsVoid, args.parameterCount), (refKinds, returnsVoid, parameterCount)); } } - var synthesizedDelegates = ArrayBuilder.GetInstance(); - GetCreatedSynthesizedDelegates(synthesizedDelegates); - if (synthesizedDelegates.Count > 0) + var anonymousDelegates = ArrayBuilder.GetInstance(); + GetCreatedAnonymousDelegates(anonymousDelegates); + if (anonymousDelegatesWithFixedTypes.Count > 0 || anonymousDelegates.Count > 0) { ReportMissingOrErroneousSymbolsForDelegates(diagnostics); - foreach (var synthesizedDelegate in synthesizedDelegates) + foreach (var anonymousDelegate in anonymousDelegatesWithFixedTypes) { - compiler.Visit(synthesizedDelegate, null); + compiler.Visit(anonymousDelegate, null); + } + foreach (var anonymousDelegate in anonymousDelegates) + { + compiler.Visit(anonymousDelegate, null); } } - synthesizedDelegates.Free(); + anonymousDelegates.Free(); + + anonymousDelegatesWithFixedTypes.Free(); } /// @@ -401,7 +541,25 @@ private void GetCreatedAnonymousTypeTemplates(ArrayBuilder builder) + { + Debug.Assert(!builder.Any()); + var anonymousDelegates = _lazyAnonymousDelegates; + if (anonymousDelegates != null) + { + foreach (var template in anonymousDelegates.Values) + { + if (ReferenceEquals(template.Manager, this) && template.HasFixedTypes) + { + builder.Add(template); + } + } + // Sort types and delegates using smallest location + builder.Sort(new AnonymousTypeOrDelegateComparer(this.Compilation)); } } @@ -409,45 +567,45 @@ private void GetCreatedAnonymousTypeTemplates(ArrayBuilder - private void GetCreatedSynthesizedDelegates(ArrayBuilder builder) + private void GetCreatedAnonymousDelegates(ArrayBuilder builder) { Debug.Assert(!builder.Any()); - var delegates = _lazySynthesizedDelegates; + var delegates = _lazyAnonymousDelegates; if (delegates != null) { foreach (var template in delegates.Values) { - if (ReferenceEquals(template.Manager, this)) + if (ReferenceEquals(template.Manager, this) && !template.HasFixedTypes) { - builder.Add(template.Delegate); + builder.Add(template); } } builder.Sort(SynthesizedDelegateSymbolComparer.Instance); } } - private class SynthesizedDelegateSymbolComparer : IComparer + private class SynthesizedDelegateSymbolComparer : IComparer { public static readonly SynthesizedDelegateSymbolComparer Instance = new SynthesizedDelegateSymbolComparer(); - public int Compare(SynthesizedDelegateSymbol x, SynthesizedDelegateSymbol y) + public int Compare(AnonymousDelegateTemplateSymbol x, AnonymousDelegateTemplateSymbol y) { return x.MetadataName.CompareTo(y.MetadataName); } } - internal IReadOnlyDictionary GetSynthesizedDelegates() + internal IReadOnlyDictionary GetAnonymousDelegates() { var result = new Dictionary(); - var synthesizedDelegates = ArrayBuilder.GetInstance(); - GetCreatedSynthesizedDelegates(synthesizedDelegates); - foreach (var delegateSymbol in synthesizedDelegates) + var anonymousDelegates = ArrayBuilder.GetInstance(); + GetCreatedAnonymousDelegates(anonymousDelegates); + foreach (var delegateSymbol in anonymousDelegates) { var key = new CodeAnalysis.Emit.SynthesizedDelegateKey(delegateSymbol.MetadataName); var value = new CodeAnalysis.Emit.SynthesizedDelegateValue(delegateSymbol.GetCciAdapter()); result.Add(key, value); } - synthesizedDelegates.Free(); + anonymousDelegates.Free(); return result; } @@ -455,9 +613,7 @@ public int Compare(SynthesizedDelegateSymbol x, SynthesizedDelegateSymbol y) { var result = new Dictionary(); var templates = ArrayBuilder.GetInstance(); - // Get anonymous types but not synthesized delegates. (Delegate types are - // not reused across generations since reuse would add complexity (such - // as parsing delegate type names from metadata) without a clear benefit.) + // Get anonymous types. GetCreatedAnonymousTypeTemplates(templates); foreach (AnonymousTypeTemplateSymbol template in templates) { @@ -470,6 +626,24 @@ public int Compare(SynthesizedDelegateSymbol x, SynthesizedDelegateSymbol y) return result; } + internal IReadOnlyDictionary GetAnonymousDelegatesWithFixedTypes() + { + var result = new Dictionary(); + var templates = ArrayBuilder.GetInstance(); + // Get anonymous delegates with fixed types (distinct from + // anonymous delegates from GetAnonymousDelegates() above). + GetCreatedAnonymousDelegatesWithFixedTypes(templates); + foreach (var template in templates) + { + var nameAndIndex = template.NameAndIndex; + var name = nameAndIndex.Name; + var value = new AnonymousTypeValue(name, nameAndIndex.Index, template.GetCciAdapter()); + result.Add(name, value); + } + templates.Free(); + return result; + } + /// /// Returns all templates owned by this type manager /// @@ -484,10 +658,15 @@ internal ImmutableArray GetAllCreatedTemplates() builder.AddRange(anonymousTypes); anonymousTypes.Free(); - var synthesizedDelegates = ArrayBuilder.GetInstance(); - GetCreatedSynthesizedDelegates(synthesizedDelegates); - builder.AddRange(synthesizedDelegates); - synthesizedDelegates.Free(); + var anonymousDelegatesWithFixedTypes = ArrayBuilder.GetInstance(); + GetCreatedAnonymousDelegatesWithFixedTypes(anonymousDelegatesWithFixedTypes); + builder.AddRange(anonymousDelegatesWithFixedTypes); + anonymousDelegatesWithFixedTypes.Free(); + + var anonymousDelegates = ArrayBuilder.GetInstance(); + GetCreatedAnonymousDelegates(anonymousDelegates); + builder.AddRange(anonymousDelegates); + anonymousDelegates.Free(); return builder.ToImmutableAndFree(); } @@ -542,18 +721,18 @@ internal static MethodSymbol TranslateAnonymousTypeMethodSymbol(MethodSymbol met } /// - /// Comparator being used for stable ordering in anonymous type indices. + /// Comparator being used for stable ordering in anonymous type or delegate indices. /// - private sealed class AnonymousTypeComparer : IComparer + private sealed class AnonymousTypeOrDelegateComparer : IComparer { private readonly CSharpCompilation _compilation; - public AnonymousTypeComparer(CSharpCompilation compilation) + public AnonymousTypeOrDelegateComparer(CSharpCompilation compilation) { _compilation = compilation; } - public int Compare(AnonymousTypeTemplateSymbol x, AnonymousTypeTemplateSymbol y) + public int Compare(AnonymousTypeOrDelegateTemplateSymbol x, AnonymousTypeOrDelegateTemplateSymbol y) { if ((object)x == (object)y) { diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs new file mode 100644 index 0000000000000..66b9a61e63a21 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs @@ -0,0 +1,188 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Emit; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal sealed partial class AnonymousTypeManager + { + internal sealed class AnonymousDelegateTemplateSymbol : AnonymousTypeOrDelegateTemplateSymbol + { + private readonly ImmutableArray _members; + + /// + /// True if any of the delegate parameter types or return type are + /// fixed types rather than type parameters. + /// + internal readonly bool HasFixedTypes; + + /// + /// A delegate type where the parameter types and return type + /// of the delegate signature are type parameters. + /// + internal AnonymousDelegateTemplateSymbol( + AnonymousTypeManager manager, + string name, + TypeSymbol objectType, + TypeSymbol intPtrType, + TypeSymbol? voidReturnTypeOpt, + int parameterCount, + RefKindVector refKinds) + : base(manager, Location.None) // Location is not needed since NameAndIndex is set explicitly below. + { + Debug.Assert(refKinds.IsNull || parameterCount == refKinds.Capacity - (voidReturnTypeOpt is { } ? 0 : 1)); + + HasFixedTypes = false; + TypeParameters = createTypeParameters(this, parameterCount, returnsVoid: voidReturnTypeOpt is { }); + NameAndIndex = new NameAndIndex(name, index: 0); + + var constructor = new SynthesizedDelegateConstructor(this, objectType, intPtrType); + // https://github.com/dotnet/roslyn/issues/56808: Synthesized delegates should include BeginInvoke() and EndInvoke(). + var invokeMethod = createInvokeMethod(this, refKinds, voidReturnTypeOpt); + _members = ImmutableArray.Create(constructor, invokeMethod); + + static SynthesizedDelegateInvokeMethod createInvokeMethod(AnonymousDelegateTemplateSymbol containingType, RefKindVector refKinds, TypeSymbol? voidReturnTypeOpt) + { + var typeParams = containingType.TypeParameters; + + int parameterCount = typeParams.Length - (voidReturnTypeOpt is null ? 1 : 0); + var parameterTypes = ArrayBuilder.GetInstance(parameterCount); + var parameterRefKinds = ArrayBuilder.GetInstance(parameterCount); + for (int i = 0; i < parameterCount; i++) + { + parameterTypes.Add(TypeWithAnnotations.Create(typeParams[i])); + parameterRefKinds.Add(refKinds.IsNull ? RefKind.None : refKinds[i]); + } + + // if we are given Void type the method returns Void, otherwise its return type is the last type parameter of the delegate: + var returnType = TypeWithAnnotations.Create(voidReturnTypeOpt ?? typeParams[parameterCount]); + var returnRefKind = (refKinds.IsNull || voidReturnTypeOpt is { }) ? RefKind.None : refKinds[parameterCount]; + + var method = new SynthesizedDelegateInvokeMethod(containingType, parameterTypes, parameterRefKinds, returnType, returnRefKind); + parameterRefKinds.Free(); + parameterTypes.Free(); + return method; + } + + static ImmutableArray createTypeParameters(AnonymousDelegateTemplateSymbol containingType, int parameterCount, bool returnsVoid) + { + var typeParameters = ArrayBuilder.GetInstance(parameterCount + (returnsVoid ? 0 : 1)); + for (int i = 0; i < parameterCount; i++) + { + typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, i, "T" + (i + 1))); + } + + if (!returnsVoid) + { + typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, parameterCount, "TResult")); + } + + return typeParameters.ToImmutableAndFree(); + } + } + + /// + /// A delegate type where at least one of the parameter types or return type + /// of the delegate signature is a fixed type not a type parameter. + /// + internal AnonymousDelegateTemplateSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr, ImmutableArray typeParametersToSubstitute) + : base(manager, typeDescr.Location) + { + // AnonymousTypeOrDelegateComparer requires an actual location. + Debug.Assert(SmallestLocation != null); + Debug.Assert(SmallestLocation != Location.None); + + HasFixedTypes = true; + + TypeMap typeMap; + int typeParameterCount = typeParametersToSubstitute.Length; + if (typeParameterCount == 0) + { + TypeParameters = ImmutableArray.Empty; + typeMap = TypeMap.Empty; + } + else + { + var typeParameters = ArrayBuilder.GetInstance(typeParameterCount); + for (int i = 0; i < typeParameterCount; i++) + { + typeParameters.Add(new AnonymousTypeParameterSymbol(this, i, "T" + (i + 1))); + } + TypeParameters = typeParameters.ToImmutableAndFree(); + typeMap = new TypeMap(typeParametersToSubstitute, TypeParameters, allowAlpha: true); + } + + var constructor = new SynthesizedDelegateConstructor(this, manager.System_Object, manager.System_IntPtr); + // https://github.com/dotnet/roslyn/issues/56808: Synthesized delegates should include BeginInvoke() and EndInvoke(). + var invokeMethod = createInvokeMethod(this, typeDescr.Fields, typeMap); + _members = ImmutableArray.Create(constructor, invokeMethod); + + static SynthesizedDelegateInvokeMethod createInvokeMethod( + AnonymousDelegateTemplateSymbol containingType, + ImmutableArray fields, + TypeMap typeMap) + { + var parameterCount = fields.Length - 1; + var parameterTypes = ArrayBuilder.GetInstance(parameterCount); + var parameterRefKinds = ArrayBuilder.GetInstance(parameterCount); + for (int i = 0; i < parameterCount; i++) + { + var parameter = fields[i]; + parameterTypes.Add(typeMap.SubstituteType(parameter.Type)); + parameterRefKinds.Add(parameter.RefKind); + } + + var returnParameter = fields[^1]; + var returnType = typeMap.SubstituteType(returnParameter.Type); + var returnRefKind = returnParameter.RefKind; + + var method = new SynthesizedDelegateInvokeMethod(containingType, parameterTypes, parameterRefKinds, returnType, returnRefKind); + parameterRefKinds.Free(); + parameterTypes.Free(); + return method; + } + } + + // AnonymousTypeOrDelegateComparer should not be calling this property for delegate + // types since AnonymousTypeOrDelegateComparer is only used during emit and we + // should only be emitting delegate types inferred from distinct locations in source. + internal override string TypeDescriptorKey => throw new System.NotImplementedException(); + + public override TypeKind TypeKind => TypeKind.Delegate; + + public override IEnumerable MemberNames => GetMembers().SelectAsArray(member => member.Name); + + internal override bool HasDeclaredRequiredMembers => false; + + public override ImmutableArray GetMembers() => _members; + + public override ImmutableArray GetMembers(string name) => GetMembers().WhereAsArray((member, name) => member.Name == name, name); + + internal override IEnumerable GetFieldsToEmit() => SpecializedCollections.EmptyEnumerable(); + + internal override ImmutableArray GetInterfacesToEmit() => ImmutableArray.Empty; + + internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList? basesBeingResolved = null) => ImmutableArray.Empty; + + internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics => Manager.System_MulticastDelegate; + + public override ImmutableArray TypeParameters { get; } + + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + + var compilation = ContainingSymbol.DeclaringCompilation; + AddSynthesizedAttribute(ref attributes, + compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + } + } + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs index 41ec114a2b5e5..9e0c07b2cc20f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs @@ -8,8 +8,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Threading; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; @@ -19,27 +17,12 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed partial class AnonymousTypeManager { - internal sealed class NameAndIndex - { - public NameAndIndex(string name, int index) - { - this.Name = name; - this.Index = index; - } - - public readonly string Name; - public readonly int Index; - } - /// /// Represents an anonymous type 'template' which is a generic type to be used for all - /// anonymous type having the same structure, i.e. the same number of fields and field names. + /// anonymous types having the same structure, i.e. the same number of fields and field names. /// - internal sealed class AnonymousTypeTemplateSymbol : NamedTypeSymbol + internal sealed class AnonymousTypeTemplateSymbol : AnonymousTypeOrDelegateTemplateSymbol { - /// Name to be used as metadata name during emit - private NameAndIndex _nameAndIndex; - private readonly ImmutableArray _typeParameters; private readonly ImmutableArray _members; @@ -53,26 +36,10 @@ internal sealed class AnonymousTypeTemplateSymbol : NamedTypeSymbol /// Maps member names to symbol(s) private readonly MultiDictionary _nameToSymbols = new MultiDictionary(); - /// Anonymous type manager owning this template - internal readonly AnonymousTypeManager Manager; - - /// Smallest location of the template, actually contains the smallest location - /// of all the anonymous type instances created using this template during EMIT - private Location _smallestLocation; - - /// Key pf the anonymous type descriptor - internal readonly string TypeDescriptorKey; - - internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr) + internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr) : + base(manager, typeDescr.Location) { - this.Manager = manager; this.TypeDescriptorKey = typeDescr.Key; - _smallestLocation = typeDescr.Location; - - // Will be set when the type's metadata is ready to be emitted, - // .Name will throw exception if requested - // before that moment. - _nameAndIndex = null; int fieldsCount = typeDescr.Fields.Length; int membersCount = fieldsCount * 3 + 1; @@ -123,70 +90,17 @@ internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousType new AnonymousTypeToStringMethodSymbol(this)); } - protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) - => throw ExceptionUtilities.Unreachable; - internal AnonymousTypeKey GetAnonymousTypeKey() { var properties = Properties.SelectAsArray(p => new AnonymousTypeKeyField(p.Name, isKey: false, ignoreCase: false)); return new AnonymousTypeKey(properties); } - /// - /// Smallest location of the template, actually contains the smallest location - /// of all the anonymous type instances created using this template during EMIT; - /// - /// NOTE: if this property is queried, smallest location must not be null. - /// - internal Location SmallestLocation - { - get - { - Debug.Assert(_smallestLocation != null); - return _smallestLocation; - } - } + internal override string TypeDescriptorKey { get; } - internal NameAndIndex NameAndIndex - { - get - { - return _nameAndIndex; - } - set - { - var oldValue = Interlocked.CompareExchange(ref _nameAndIndex, value, null); - Debug.Assert(oldValue == null || - ((oldValue.Name == value.Name) && (oldValue.Index == value.Index))); - } - } - - /// - /// In emit phase every time a created anonymous type is referenced we try to store the lowest - /// location of the template. It will be used for ordering templates and assigning emitted type names. - /// - internal void AdjustLocation(Location location) + public override TypeKind TypeKind { - Debug.Assert(location.IsInSource); - - while (true) - { - // Loop until we managed to set location OR we detected that we don't need to set it - // in case 'location' in type descriptor is bigger that the one in smallestLocation - - Location currentSmallestLocation = _smallestLocation; - if (currentSmallestLocation != null && this.Manager.Compilation.CompareSourceLocations(currentSmallestLocation, location) < 0) - { - // The template's smallest location do not need to be changed - return; - } - - if (ReferenceEquals(Interlocked.CompareExchange(ref _smallestLocation, location, currentSmallestLocation), currentSmallestLocation)) - { - // Changed successfully, proceed to updating the fields - return; - } - } + get { return TypeKind.Class; } } internal override bool HasDeclaredRequiredMembers => false; @@ -209,15 +123,6 @@ internal override IEnumerable GetFieldsToEmit() } } - internal override bool HasCodeAnalysisEmbeddedAttribute => false; - - internal override bool IsInterpolatedStringHandlerType => false; - - internal override ImmutableArray TypeArgumentsWithAnnotationsNoUseSiteDiagnostics - { - get { return GetTypeParametersAsTypeArguments(); } - } - public override ImmutableArray GetMembers(string name) { var symbols = _nameToSymbols[name]; @@ -230,106 +135,6 @@ public override ImmutableArray GetMembers(string name) return builder.ToImmutableAndFree(); } - internal override ImmutableArray GetEarlyAttributeDecodingMembers() - { - return this.GetMembersUnordered(); - } - - internal override ImmutableArray GetEarlyAttributeDecodingMembers(string name) - { - return this.GetMembers(name); - } - - public override IEnumerable MemberNames - { - get { return _nameToSymbols.Keys; } - } - - public override Symbol ContainingSymbol - { - get { return this.Manager.Compilation.SourceModule.GlobalNamespace; } - } - - public override string Name - { - get { return _nameAndIndex.Name; } - } - - internal override bool HasSpecialName - { - get { return false; } - } - - internal override bool MangleName - { - get { return this.Arity > 0; } - } - - public override int Arity - { - get { return _typeParameters.Length; } - } - - public override bool IsImplicitlyDeclared - { - get { return true; } - } - - public override ImmutableArray TypeParameters - { - get { return _typeParameters; } - } - - public override bool IsAbstract - { - get { return false; } - } - - public sealed override bool IsRefLikeType - { - get { return false; } - } - - public sealed override bool IsReadOnly - { - get { return false; } - } - - public override bool IsSealed - { - get { return true; } - } - - public override bool MightContainExtensionMethods - { - get { return false; } - } - - public sealed override bool AreLocalsZeroed - { - get { return ContainingModule.AreLocalsZeroed; } - } - - public override ImmutableArray GetTypeMembers() - { - return ImmutableArray.Empty; - } - - public override ImmutableArray GetTypeMembers(string name) - { - return ImmutableArray.Empty; - } - - public override ImmutableArray GetTypeMembers(string name, int arity) - { - return ImmutableArray.Empty; - } - - public override Accessibility DeclaredAccessibility - { - get { return Accessibility.Internal; } - } - internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList basesBeingResolved) { return ImmutableArray.Empty; @@ -342,112 +147,16 @@ internal override ImmutableArray GetInterfacesToEmit() internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics => this.Manager.System_Object; - public override TypeKind TypeKind - { - get { return TypeKind.Class; } - } - - internal override bool IsInterface - { - get { return false; } - } - - public override ImmutableArray Locations - { - get { return ImmutableArray.Empty; } - } - - public override ImmutableArray DeclaringSyntaxReferences - { - get - { - return ImmutableArray.Empty; - } - } - - public override bool IsStatic - { - get { return false; } - } - - public override NamedTypeSymbol ConstructedFrom - { - get { return this; } - } - - internal override NamedTypeSymbol GetDeclaredBaseType(ConsList basesBeingResolved) - { - return this.Manager.System_Object; - } - - internal override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) - { - return ImmutableArray.Empty; - } - - internal override bool ShouldAddWinRTMembers - { - get { return false; } - } - - internal override bool IsWindowsRuntimeImport - { - get { return false; } - } - - internal override bool IsComImport - { - get { return false; } - } - - internal sealed override ObsoleteAttributeData ObsoleteAttributeData - { - get { return null; } - } - - internal override TypeLayout Layout - { - get { return default(TypeLayout); } - } - - internal override CharSet MarshallingCharSet - { - get { return DefaultMarshallingCharSet; } - } - - public override bool IsSerializable - { - get { return false; } - } - - internal override bool HasDeclarativeSecurity - { - get { return false; } - } - - internal override IEnumerable GetSecurityInformation() - { - throw ExceptionUtilities.Unreachable; - } - - internal override ImmutableArray GetAppliedConditionalSymbols() + public override ImmutableArray TypeParameters { - return ImmutableArray.Empty; + get { return _typeParameters; } } - internal override AttributeUsageInfo GetAttributeUsageInfo() + public override IEnumerable MemberNames { - return AttributeUsageInfo.Null; + get { return _nameToSymbols.Keys; } } - internal sealed override NamedTypeSymbol AsNativeInteger() => throw ExceptionUtilities.Unreachable; - - internal sealed override NamedTypeSymbol NativeIntegerUnderlyingType => null; - - internal override bool IsRecord => false; - - internal override bool IsRecordStruct => false; - internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) { base.AddSynthesizedAttributes(moduleBuilder, ref attributes); @@ -513,13 +222,6 @@ private SynthesizedAttributeData TrySynthesizeDebuggerDisplayAttribute() WellKnownMember.System_Diagnostics_DebuggerDisplayAttribute__Type, new TypedConstant(Manager.System_String, TypedConstantKind.Primitive, "")))); } - - internal override bool HasPossibleWellKnownCloneMethod() => false; - - internal override IEnumerable<(MethodSymbol Body, MethodSymbol Implemented)> SynthesizedInterfaceMethodImpls() - { - return SpecializedCollections.EmptyEnumerable<(MethodSymbol Body, MethodSymbol Implemented)>(); - } } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs new file mode 100644 index 0000000000000..7f335aea333b8 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs @@ -0,0 +1,321 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal sealed partial class AnonymousTypeManager + { + internal sealed class NameAndIndex + { + public NameAndIndex(string name, int index) + { + this.Name = name; + this.Index = index; + } + + public readonly string Name; + public readonly int Index; + } + + internal abstract class AnonymousTypeOrDelegateTemplateSymbol : NamedTypeSymbol + { + /// Name to be used as metadata name during emit + private NameAndIndex? _nameAndIndex; + + /// Smallest location of the template, actually contains the smallest location + /// of all the anonymous type instances created using this template during EMIT + private Location _smallestLocation; + + /// Anonymous type manager owning this template + internal readonly AnonymousTypeManager Manager; + + internal AnonymousTypeOrDelegateTemplateSymbol(AnonymousTypeManager manager, Location location) + { + this.Manager = manager; + _smallestLocation = location; + + // Will be set when the type's metadata is ready to be emitted, + // .Name will throw exception if requested + // before that moment. + _nameAndIndex = null; + } + + internal abstract string TypeDescriptorKey { get; } + + protected sealed override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) + => throw ExceptionUtilities.Unreachable; + + /// + /// Smallest location of the template, actually contains the smallest location + /// of all the anonymous type instances created using this template during EMIT; + /// + /// NOTE: if this property is queried, smallest location must not be null. + /// + internal Location SmallestLocation + { + get + { + Debug.Assert(_smallestLocation != null); + return _smallestLocation; + } + } + + internal NameAndIndex? NameAndIndex + { + get + { + return _nameAndIndex; + } + set + { + Debug.Assert(value != null); + var oldValue = Interlocked.CompareExchange(ref _nameAndIndex, value, null); + Debug.Assert(oldValue == null || + ((oldValue.Name == value.Name) && (oldValue.Index == value.Index))); + } + } + + /// + /// In emit phase every time a created anonymous type is referenced we try to store the lowest + /// location of the template. It will be used for ordering templates and assigning emitted type names. + /// + internal void AdjustLocation(Location location) + { + Debug.Assert(location.IsInSource); + + while (true) + { + // Loop until we managed to set location OR we detected that we don't need to set it + // in case 'location' in type descriptor is bigger that the one in smallestLocation + + Location currentSmallestLocation = _smallestLocation; + if (currentSmallestLocation != null && this.Manager.Compilation.CompareSourceLocations(currentSmallestLocation, location) < 0) + { + // The template's smallest location do not need to be changed + return; + } + + if (ReferenceEquals(Interlocked.CompareExchange(ref _smallestLocation, location, currentSmallestLocation), currentSmallestLocation)) + { + // Changed successfully, proceed to updating the fields + return; + } + } + } + + internal sealed override bool HasCodeAnalysisEmbeddedAttribute => false; + + internal sealed override bool IsInterpolatedStringHandlerType => false; + + internal sealed override ImmutableArray GetEarlyAttributeDecodingMembers() + { + return this.GetMembersUnordered(); + } + + internal sealed override ImmutableArray GetEarlyAttributeDecodingMembers(string name) + { + return this.GetMembers(name); + } + + public sealed override Symbol ContainingSymbol + { + get { return this.Manager.Compilation.SourceModule.GlobalNamespace; } + } + + public sealed override string Name + { + get { return _nameAndIndex!.Name; } + } + + internal sealed override bool HasSpecialName + { + get { return false; } + } + + public sealed override bool IsImplicitlyDeclared + { + get { return true; } + } + + public sealed override bool IsAbstract + { + get { return false; } + } + + public sealed override bool IsRefLikeType + { + get { return false; } + } + + public sealed override bool IsReadOnly + { + get { return false; } + } + + public sealed override bool IsSealed + { + get { return true; } + } + + public sealed override bool MightContainExtensionMethods + { + get { return false; } + } + + public sealed override bool AreLocalsZeroed + { + get { return ContainingModule.AreLocalsZeroed; } + } + + public sealed override ImmutableArray GetTypeMembers() + { + return ImmutableArray.Empty; + } + + public sealed override ImmutableArray GetTypeMembers(string name) + { + return ImmutableArray.Empty; + } + + public sealed override ImmutableArray GetTypeMembers(string name, int arity) + { + return ImmutableArray.Empty; + } + + public sealed override Accessibility DeclaredAccessibility + { + get { return Accessibility.Internal; } + } + + internal sealed override bool IsInterface + { + get { return false; } + } + + public sealed override ImmutableArray Locations + { + get { return ImmutableArray.Empty; } + } + + public sealed override ImmutableArray DeclaringSyntaxReferences + { + get { return ImmutableArray.Empty; } + } + + public sealed override bool IsStatic + { + get { return false; } + } + + public sealed override NamedTypeSymbol ConstructedFrom + { + get { return this; } + } + + internal abstract override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics { get; } + + internal sealed override NamedTypeSymbol GetDeclaredBaseType(ConsList basesBeingResolved) + { + return this.Manager.System_Object; + } + + internal sealed override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) + { + return ImmutableArray.Empty; + } + + internal sealed override bool MangleName + { + get { return this.Arity > 0; } + } + + internal sealed override ImmutableArray TypeArgumentsWithAnnotationsNoUseSiteDiagnostics + { + get { return GetTypeParametersAsTypeArguments(); } + } + + public sealed override int Arity + { + get { return TypeParameters.Length; } + } + + internal sealed override bool ShouldAddWinRTMembers + { + get { return false; } + } + + internal sealed override bool IsWindowsRuntimeImport + { + get { return false; } + } + + internal sealed override bool IsComImport + { + get { return false; } + } + + internal sealed override ObsoleteAttributeData? ObsoleteAttributeData + { + get { return null; } + } + + internal sealed override TypeLayout Layout + { + get { return default(TypeLayout); } + } + + internal sealed override CharSet MarshallingCharSet + { + get { return DefaultMarshallingCharSet; } + } + + public sealed override bool IsSerializable + { + get { return false; } + } + + internal sealed override bool HasDeclarativeSecurity + { + get { return false; } + } + + internal sealed override IEnumerable GetSecurityInformation() + { + throw ExceptionUtilities.Unreachable; + } + + internal sealed override ImmutableArray GetAppliedConditionalSymbols() + { + return ImmutableArray.Empty; + } + + internal sealed override AttributeUsageInfo GetAttributeUsageInfo() + { + return AttributeUsageInfo.Null; + } + + internal sealed override NamedTypeSymbol AsNativeInteger() => throw ExceptionUtilities.Unreachable; + + internal sealed override NamedTypeSymbol? NativeIntegerUnderlyingType => null; + + internal sealed override bool IsRecord => false; + + internal sealed override bool IsRecordStruct => false; + + internal sealed override bool HasPossibleWellKnownCloneMethod() => false; + + internal sealed override IEnumerable<(MethodSymbol Body, MethodSymbol Implemented)> SynthesizedInterfaceMethodImpls() + { + return SpecializedCollections.EmptyEnumerable<(MethodSymbol Body, MethodSymbol Implemented)>(); + } + } + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs index 3d5fdb7b3d910..02c70ada96c12 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs @@ -4,11 +4,13 @@ #nullable disable +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.CSharp.Emit; +using Microsoft.CodeAnalysis.RuntimeMembers; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; @@ -469,15 +471,34 @@ public virtual int TupleElementIndex get { // wrapped tuple fields already have this information and override this property - Debug.Assert(!(this is TupleElementFieldSymbol or TupleErrorFieldSymbol)); + Debug.Assert(!(this is TupleElementFieldSymbol or TupleErrorFieldSymbol or Retargeting.RetargetingFieldSymbol)); + if (!ContainingType.IsTupleType) + { + return -1; + } - var map = ContainingType.TupleFieldDefinitionsToIndexMap; - if (map is object && map.TryGetValue(this.OriginalDefinition, out int index)) + if (!ContainingType.IsDefinition) { - return index; + return this.OriginalDefinition.TupleElementIndex; } - return -1; + var tupleElementPosition = NamedTypeSymbol.MatchesCanonicalTupleElementName(Name); + int arity = ContainingType.Arity; + if (tupleElementPosition <= 0 || tupleElementPosition > arity) + { + // ex: no "Item2" in 'ValueTuple' + return -1; + } + Debug.Assert(tupleElementPosition < NamedTypeSymbol.ValueTupleRestPosition); + + WellKnownMember wellKnownMember = NamedTypeSymbol.GetTupleTypeMember(arity, tupleElementPosition); + MemberDescriptor descriptor = WellKnownMembers.GetDescriptor(wellKnownMember); + Symbol found = CSharpCompilation.GetRuntimeMember(ImmutableArray.Create(this), descriptor, CSharpCompilation.SpecialMembersSignatureComparer.Instance, + accessWithinOpt: null); // force lookup of public members only + + return found is not null + ? tupleElementPosition - 1 + : -1; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs index 8f77374f477ce..57d5254964fd4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using Roslyn.Utilities; @@ -15,6 +16,7 @@ internal sealed class FunctionPointerParameterSymbol : ParameterSymbol public FunctionPointerParameterSymbol(TypeWithAnnotations typeWithAnnotations, RefKind refKind, int ordinal, FunctionPointerMethodSymbol containingSymbol, ImmutableArray refCustomModifiers) { + Debug.Assert(typeWithAnnotations.HasType); TypeWithAnnotations = typeWithAnnotations; RefKind = refKind; Ordinal = ordinal; diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs index 7d06f22c26224..1a0280d0473e5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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; @@ -141,7 +139,7 @@ public bool TryGetFlowAnalysisAnnotations(out FlowAnalysisAnnotations value) private readonly PEModuleSymbol _moduleSymbol; private ImmutableArray _lazyCustomAttributes; - private ConstantValue _lazyDefaultValue = ConstantValue.Unset; + private ConstantValue? _lazyDefaultValue = ConstantValue.Unset; private ThreeState _lazyIsParams; private static readonly ImmutableArray s_defaultStringHandlerAttributeIndexes = ImmutableArray.Create(int.MinValue); @@ -298,6 +296,7 @@ private PEParameterSymbol( Debug.Assert(refKind == this.RefKind); Debug.Assert(hasNameInMetadata == this.HasNameInMetadata); + Debug.Assert(_name is not null); } private bool HasNameInMetadata @@ -463,14 +462,14 @@ internal override bool HasMetadataConstantValue /// /// Internal for testing. Non-test code should use . /// - internal ConstantValue ImportConstantValue(bool ignoreAttributes = false) + internal ConstantValue? ImportConstantValue(bool ignoreAttributes = false) { Debug.Assert(!_handle.IsNil); // Metadata Spec 22.33: // 6. If Flags.HasDefault = 1 then this row [of Param table] shall own exactly one row in the Constant table [ERROR] // 7. If Flags.HasDefault = 0, then there shall be no rows in the Constant table owned by this row [ERROR] - ConstantValue value = null; + ConstantValue? value = null; if ((_flags & ParameterAttributes.HasDefault) != 0) { @@ -485,7 +484,7 @@ internal ConstantValue ImportConstantValue(bool ignoreAttributes = false) return value; } - internal override ConstantValue ExplicitDefaultConstantValue + internal override ConstantValue? ExplicitDefaultConstantValue { get { @@ -495,7 +494,7 @@ internal override ConstantValue ExplicitDefaultConstantValue // From the C# point of view, there is no need to import a parameter's default value // if the language isn't going to treat it as optional. However, we might need metadata constant value for NoPia. // NOTE: Ignoring attributes for non-Optional parameters disrupts round-tripping, but the trade-off seems acceptable. - ConstantValue value = ImportConstantValue(ignoreAttributes: !IsMetadataOptional); + ConstantValue? value = ImportConstantValue(ignoreAttributes: !IsMetadataOptional); Interlocked.CompareExchange(ref _lazyDefaultValue, value, ConstantValue.Unset); } @@ -503,10 +502,10 @@ internal override ConstantValue ExplicitDefaultConstantValue } } - private ConstantValue GetDefaultDecimalOrDateTimeValue() + private ConstantValue? GetDefaultDecimalOrDateTimeValue() { Debug.Assert(!_handle.IsNil); - ConstantValue value = null; + ConstantValue? value = null; // It is possible in Visual Basic for a parameter of object type to have a default value of DateTime type. // If it's present, use it. We'll let the call-site figure out whether it can actually be used. diff --git a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs index 9487c7a2ab270..5b402f412f8a2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs @@ -373,6 +373,8 @@ internal sealed class NativeIntegerParameterSymbol : WrappedParameterSymbol internal NativeIntegerParameterSymbol(NativeIntegerTypeSymbol containingType, NativeIntegerMethodSymbol container, ParameterSymbol underlyingParameter) : base(underlyingParameter) { + Debug.Assert(container != null); + _containingType = containingType; _container = container; NativeIntegerTypeSymbol.VerifyEquality(this, underlyingParameter); diff --git a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs index f1f0dc2642df8..60d51dd0d52af 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -79,7 +78,7 @@ protected sealed override Symbol OriginalSymbolDefinition /// Null if no specific marshalling information is available for the parameter. /// /// PE symbols don't provide this information and always return null. - internal abstract MarshalPseudoCustomAttributeData MarshallingInformation { get; } + internal abstract MarshalPseudoCustomAttributeData? MarshallingInformation { get; } /// /// Returns the marshalling type of this parameter, or 0 if marshalling information isn't available. @@ -195,6 +194,7 @@ public bool IsOptional /// /// The default value can be obtained with property. /// + [MemberNotNullWhen(true, nameof(ExplicitDefaultConstantValue))] public bool HasExplicitDefaultValue { get @@ -224,7 +224,7 @@ public bool HasExplicitDefaultValue /// /// The parameter has no default value. [DebuggerBrowsable(DebuggerBrowsableState.Never)] - public object ExplicitDefaultValue + public object? ExplicitDefaultValue { get { @@ -237,7 +237,6 @@ public object ExplicitDefaultValue } } -#nullable enable /// /// Returns the default value constant of the parameter, /// or null if the parameter doesn't have a default value or @@ -250,7 +249,6 @@ public object ExplicitDefaultValue /// (i.e. even non-optional parameters can have default values). /// internal abstract ConstantValue? ExplicitDefaultConstantValue { get; } -#nullable disable /// /// Gets the kind of this symbol. @@ -385,7 +383,7 @@ public virtual bool IsThis /// Returns data decoded from Obsolete attribute or null if there is no Obsolete attribute. /// This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet. /// - internal sealed override ObsoleteAttributeData ObsoleteAttributeData + internal sealed override ObsoleteAttributeData? ObsoleteAttributeData { get { return null; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs index 49220458b4803..1504282ae7e3c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/ParameterSymbol.cs @@ -62,8 +62,6 @@ IParameterSymbol IParameterSymbol.OriginalDefinition bool IParameterSymbol.IsParams => _underlying.IsParams; - bool IParameterSymbol.IsNullChecked => _underlying.IsNullChecked; - bool IParameterSymbol.IsOptional => _underlying.IsOptional; bool IParameterSymbol.IsThis => _underlying.IsThis; diff --git a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs index 079d740aace9e..acaf3d1f1e2d6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs @@ -588,6 +588,8 @@ public override int GetHashCode() return _reducedFrom.GetHashCode(); } +#nullable enable + private sealed class ReducedExtensionMethodParameterSymbol : WrappedParameterSymbol { private readonly ReducedExtensionMethodSymbol _containingMethod; @@ -595,6 +597,7 @@ private sealed class ReducedExtensionMethodParameterSymbol : WrappedParameterSym public ReducedExtensionMethodParameterSymbol(ReducedExtensionMethodSymbol containingMethod, ParameterSymbol underlyingParameter) : base(underlyingParameter) { + Debug.Assert(containingMethod != null); Debug.Assert(underlyingParameter.Ordinal > 0); _containingMethod = containingMethod; } @@ -663,7 +666,7 @@ public sealed override bool Equals(Symbol obj, TypeCompareKind compareKind) // ReferenceEquals. var other = obj as ReducedExtensionMethodParameterSymbol; - return (object)other != null && + return other is not null && this.Ordinal == other.Ordinal && this.ContainingSymbol.Equals(other.ContainingSymbol, compareKind); } @@ -673,5 +676,6 @@ public sealed override int GetHashCode() return Hash.Combine(ContainingSymbol, _underlyingParameter.Ordinal); } } +#nullable disable } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs index 13fb6fd8f15eb..d8109971d42d8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs @@ -137,20 +137,6 @@ public override ImmutableArray GetMembers(string name) return this.RetargetingTranslator.Retarget(_underlyingType.GetMembers(name)); } - public override void InitializeTupleFieldDefinitionsToIndexMap() - { - Debug.Assert(this.IsTupleType); - Debug.Assert(this.IsDefinition); // we only store a map for definitions - - var retargetedMap = new SmallDictionary(ReferenceEqualityComparer.Instance); - foreach ((FieldSymbol field, int index) in _underlyingType.TupleFieldDefinitionsToIndexMap) - { - retargetedMap.Add(this.RetargetingTranslator.Retarget(field), index); - } - - this.TupleData!.SetFieldDefinitionsToIndexMap(retargetedMap); - } - internal override IEnumerable GetFieldsToEmit() { foreach (FieldSymbol f in _underlyingType.GetFieldsToEmit()) diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingParameterSymbol.cs index 69f36b356e419..dd32f3e7212af 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingParameterSymbol.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -118,7 +116,16 @@ internal override ImmutableArray MarshallingDescriptor } } - internal sealed override CSharpCompilation DeclaringCompilation // perf, not correctness + /// + /// + /// + /// + /// This override is done for performance reasons. Lacking the override this would redirect to + /// which returns null. The override + /// short circuits the overhead in and the extra virtual + /// dispatch and just returns null. + /// + internal sealed override CSharpCompilation? DeclaringCompilation { get { return null; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs index f2f793ded6c09..d1325b7dd8a3e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyParameterSymbol.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Diagnostics; using System.Linq; @@ -106,7 +104,7 @@ public override bool Equals(Symbol obj, TypeCompareKind compareKind) } var other = obj as SignatureOnlyParameterSymbol; - return (object)other != null && + return other is not null && TypeSymbol.Equals(_type.Type, other._type.Type, compareKind) && _type.CustomModifiers.Equals(other._type.CustomModifiers) && _refCustomModifiers.SequenceEqual(other._refCustomModifiers) && diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index fd74d30be3164..910cd4273f970 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -138,9 +138,9 @@ private static ImmutableArray MakeParameters Locations { - get { return (object)_containingMethod != null ? _containingMethod.Locations : ImmutableArray.Empty; } + get { return _containingMethod is not null ? _containingMethod.Locations : ImmutableArray.Empty; } } public override ImmutableArray DeclaringSyntaxReferences @@ -73,10 +73,10 @@ public override ImmutableArray DeclaringSyntaxReferences public override Symbol ContainingSymbol { - get { return (Symbol)_containingMethod ?? _containingType; } + get { return (Symbol?)_containingMethod ?? _containingType; } } - internal override ConstantValue ExplicitDefaultConstantValue + internal override ConstantValue? ExplicitDefaultConstantValue { get { return null; } } @@ -163,7 +163,7 @@ internal override bool IsMetadataOut get { return false; } } - internal override MarshalPseudoCustomAttributeData MarshallingInformation + internal override MarshalPseudoCustomAttributeData? MarshallingInformation { get { return null; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs index ee1c79f6baba9..383aacb6b7583 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Diagnostics; @@ -113,7 +111,7 @@ public sealed override bool Equals(Symbol obj, TypeCompareKind compareKind) // ReferenceEquals. var other = obj as SubstitutedParameterSymbol; - return (object)other != null && + return other is not null && this.Ordinal == other.Ordinal && this.ContainingSymbol.Equals(other.ContainingSymbol, compareKind); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs index ea8b6e11a96e2..400d59aff0ebc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs @@ -837,6 +837,7 @@ public virtual string GetDocumentationCommentId() } } +#nullable enable /// /// Fetches the documentation comment for this element with a cancellation token. /// @@ -845,12 +846,13 @@ public virtual string GetDocumentationCommentId() /// Optionally, allow cancellation of documentation comment retrieval. /// The XML that would be written to the documentation file for the symbol. public virtual string GetDocumentationCommentXml( - CultureInfo preferredCulture = null, + CultureInfo? preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken)) { return ""; } +#nullable disable private static readonly SymbolDisplayFormat s_debuggerDisplayFormat = SymbolDisplayFormat.TestFormat diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs index f8e208cffe980..66a294e654bad 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs @@ -39,6 +39,7 @@ internal enum GeneratedNameKind IteratorFinallyMethod = 'm', BaseMethodWrapper = 'n', AsyncBuilderField = 't', + DelegateCacheContainerType = 'O', DynamicCallSiteContainerType = 'o', DynamicCallSiteField = 'p', AsyncIteratorPromiseOfValueOrEndBackingField = 'v', @@ -62,6 +63,10 @@ internal enum GeneratedNameKind internal static class GeneratedNameKindExtensions { internal static bool IsTypeName(this GeneratedNameKind kind) - => kind is GeneratedNameKind.LambdaDisplayClass or GeneratedNameKind.StateMachineType or GeneratedNameKind.DynamicCallSiteContainerType; + => kind is GeneratedNameKind.LambdaDisplayClass + or GeneratedNameKind.StateMachineType + or GeneratedNameKind.DynamicCallSiteContainerType + or GeneratedNameKind.DelegateCacheContainerType + ; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs index 51a70440192ed..bb89a163099c0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs @@ -52,9 +52,9 @@ internal static string MakeLambdaDisplayClassName(int methodOrdinal, int generat return MakeMethodScopedSynthesizedName(GeneratedNameKind.LambdaDisplayClass, methodOrdinal, generation, suffix: "DisplayClass", entityOrdinal: closureOrdinal, entityGeneration: closureGeneration); } - internal static string MakeAnonymousTypeTemplateName(int index, int submissionSlotIndex, string moduleId) + internal static string MakeAnonymousTypeOrDelegateTemplateName(int index, int submissionSlotIndex, string moduleId, bool isDelegate) { - var name = "<" + moduleId + ">f__AnonymousType" + StringExtensions.GetNumeral(index); + var name = "<" + moduleId + (isDelegate ? ">f__AnonymousDelegate" : ">f__AnonymousType") + StringExtensions.GetNumeral(index); if (submissionSlotIndex >= 0) { name += "#" + StringExtensions.GetNumeral(submissionSlotIndex); @@ -359,6 +359,9 @@ internal static string MakeDynamicCallSiteFieldName(int uniqueId) /// Produces name of the synthesized delegate symbol that encodes the parameter byref-ness and return type of the delegate. /// The arity is appended via `N suffix in MetadataName calculation since the delegate is generic. /// + /// + /// Logic here should match . + /// internal static string MakeSynthesizedDelegateName(RefKindVector byRefs, bool returnsVoid, int generation) { var pooledBuilder = PooledStringBuilder.GetInstance(); @@ -375,6 +378,12 @@ internal static string MakeSynthesizedDelegateName(RefKindVector byRefs, bool re return pooledBuilder.ToStringAndFree(); } + /// + /// Parses the name of a synthesized delegate out into the things it represents. + /// + /// + /// Logic here should match . + /// internal static bool TryParseSynthesizedDelegateName(string name, out RefKindVector byRefs, out bool returnsVoid, out int generation, out int parameterCount) { byRefs = default; @@ -390,39 +399,43 @@ internal static bool TryParseSynthesizedDelegateName(string name, out RefKindVec return false; } - // The character after the prefix should be an open brace - if (name[DelegateNamePrefixLength] != '{') - { - return false; - } - parameterCount = arity - (returnsVoid ? 0 : 1); - var lastBraceIndex = name.LastIndexOf('}'); - if (lastBraceIndex < 0) + // If there are no ref kinds encoded + // (and therefore no braces), use the end of the prefix instead. + var nameEndIndex = name.LastIndexOf('}'); + if (nameEndIndex < 0) { - return false; + nameEndIndex = DelegateNamePrefixLength - 1; } + else + { + // There should be a character after the prefix, and it should be an open brace + if (name.Length <= DelegateNamePrefixLength || name[DelegateNamePrefixLength] != '{') + { + return false; + } - // The ref kind string is between the two braces - var refKindString = name[DelegateNamePrefixLengthWithOpenBrace..lastBraceIndex]; + // If there are braces, then the ref kind string is encoded between them + var refKindString = name[DelegateNamePrefixLengthWithOpenBrace..nameEndIndex]; - if (!RefKindVector.TryParse(refKindString, arity, out byRefs)) - { - return false; + if (!RefKindVector.TryParse(refKindString, arity, out byRefs)) + { + return false; + } } // If there is a generation index it will be directly after the brace, otherwise the brace // is the last character - if (lastBraceIndex < name.Length - 1) + if (nameEndIndex < name.Length - 1) { // Format is a '#' followed by the generation number - if (name[lastBraceIndex + 1] != '#') + if (name[nameEndIndex + 1] != '#') { return false; } - if (!int.TryParse(name[(lastBraceIndex + 2)..], out generation)) + if (!int.TryParse(name[(nameEndIndex + 2)..], out generation)) { return false; } @@ -439,6 +452,40 @@ internal static string AsyncBuilderFieldName() return "<>t__builder"; } + internal static string DelegateCacheContainerType(int generation, string? methodName = null, int methodOrdinal = -1, int ownerUniqueId = -1) + { + const char NameKind = (char)GeneratedNameKind.DelegateCacheContainerType; + + var result = PooledStringBuilder.GetInstance(); + var builder = result.Builder; + + builder.Append('<').Append(methodName).Append('>').Append(NameKind); + + if (methodOrdinal > -1) + { + builder.Append(GeneratedNameConstants.SuffixSeparator).Append(methodOrdinal); + } + + if (ownerUniqueId > -1) + { + builder.Append(IdSeparator).Append(ownerUniqueId); + } + + AppendOptionalGeneration(builder, generation); + + return result.ToStringAndFree(); + } + + internal static string DelegateCacheContainerFieldName(int id, string targetMethod) + { + var result = PooledStringBuilder.GetInstance(); + var builder = result.Builder; + + builder.Append('<').Append(id).Append(">__").Append(targetMethod); + + return result.ToStringAndFree(); + } + internal static string ReusableHoistedLocalFieldName(int number) { Debug.Assert((char)GeneratedNameKind.ReusableHoistedLocalField == '7'); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs index 76f19629921d9..511c0e79b50e0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs @@ -5,6 +5,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp.Symbols @@ -55,6 +57,15 @@ internal override void GenerateMethodBodyStatements(SyntheticBoundNodeFactory F, } } + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + Debug.Assert(IsImplicitlyDeclared); + var compilation = this.DeclaringCompilation; + AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + } + internal static MethodSymbol? FindCopyConstructor(NamedTypeSymbol containingType, NamedTypeSymbol within, ref CompoundUseSiteInfo useSiteInfo) { MethodSymbol? bestCandidate = null; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs index a85df5e9f7b81..e3f3d3ce862d2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityOperatorBase.cs @@ -6,7 +6,9 @@ using System.Diagnostics; using System.Globalization; using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols @@ -73,5 +75,14 @@ protected sealed override (TypeWithAnnotations ReturnType, ImmutableArray 2; + + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + Debug.Assert(IsImplicitlyDeclared); + var compilation = this.DeclaringCompilation; + AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs index ec7928198b68e..99e854649fd35 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs @@ -3,9 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Diagnostics; using System.Globalization; using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols @@ -60,6 +63,15 @@ protected sealed override void CheckConstraintsForExplicitInterfaceType(Conversi { } + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + Debug.Assert(IsImplicitlyDeclared); + var compilation = this.DeclaringCompilation; + AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + } + protected sealed override SourceMemberMethodSymbol? BoundAttributesSource => null; internal sealed override OneOrMany> GetAttributeDeclarations() => OneOrMany.Create(default(SyntaxList)); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs index 96dcf312f9f03..dd677239e1078 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs @@ -16,22 +16,13 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { /// - /// A container synthesized for a lambda, iterator method, async method, or dynamic-sites. + /// A container synthesized for a lambda, iterator method, or async method. /// internal abstract class SynthesizedContainer : NamedTypeSymbol { private readonly ImmutableArray _typeParameters; private readonly ImmutableArray _constructedFromTypeParameters; - protected SynthesizedContainer(string name, int parameterCount, bool returnsVoid) - { - Debug.Assert(name != null); - Name = name; - TypeMap = TypeMap.Empty; - _typeParameters = CreateTypeParameters(parameterCount, returnsVoid); - _constructedFromTypeParameters = default(ImmutableArray); - } - protected SynthesizedContainer(string name, MethodSymbol containingMethod) { Debug.Assert(name != null); @@ -58,22 +49,6 @@ protected SynthesizedContainer(string name, ImmutableArray TypeMap = typeMap; } - private ImmutableArray CreateTypeParameters(int parameterCount, bool returnsVoid) - { - var typeParameters = ArrayBuilder.GetInstance(parameterCount + (returnsVoid ? 0 : 1)); - for (int i = 0; i < parameterCount; i++) - { - typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(this, i, "T" + (i + 1))); - } - - if (!returnsVoid) - { - typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(this, parameterCount, "TResult")); - } - - return typeParameters.ToImmutableAndFree(); - } - internal TypeMap TypeMap { get; } internal virtual MethodSymbol Constructor => null; @@ -102,9 +77,6 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) => throw ExceptionUtilities.Unreachable; - /// - /// Note: Can be default if this SynthesizedContainer was constructed with - /// internal ImmutableArray ConstructedFromTypeParameters => _constructedFromTypeParameters; public sealed override ImmutableArray TypeParameters => _typeParameters; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs index 3f312257b1ce5..e5c17ffc70887 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs @@ -5,118 +5,11 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { - /// - /// Dynamic call-site delegate, for call-sites that do not - /// match System.Action or System.Func signatures. - /// - internal sealed class SynthesizedDelegateSymbol : SynthesizedContainer - { - private readonly NamespaceOrTypeSymbol _containingSymbol; - private readonly MethodSymbol _constructor; - private readonly MethodSymbol _invoke; - - public SynthesizedDelegateSymbol( - NamespaceOrTypeSymbol containingSymbol, - string name, - TypeSymbol objectType, - TypeSymbol intPtrType, - TypeSymbol? voidReturnTypeOpt, - int parameterCount, - RefKindVector refKinds) - : base(name, parameterCount, returnsVoid: voidReturnTypeOpt is not null) - { - Debug.Assert(refKinds.IsNull || parameterCount == refKinds.Capacity - (voidReturnTypeOpt is { } ? 0 : 1)); - - _containingSymbol = containingSymbol; - _constructor = new SynthesizedDelegateConstructor(this, objectType, intPtrType); - _invoke = createInvokeMethod(this, refKinds, voidReturnTypeOpt); - - static SynthesizedDelegateInvokeMethod createInvokeMethod(SynthesizedDelegateSymbol containingType, RefKindVector refKinds, TypeSymbol? voidReturnTypeOpt) - { - var typeParams = containingType.TypeParameters; - - int parameterCount = typeParams.Length - (voidReturnTypeOpt is null ? 1 : 0); - var parameterTypes = ArrayBuilder.GetInstance(parameterCount); - var parameterRefKinds = ArrayBuilder.GetInstance(parameterCount); - for (int i = 0; i < parameterCount; i++) - { - parameterTypes.Add(TypeWithAnnotations.Create(typeParams[i])); - parameterRefKinds.Add(refKinds.IsNull ? RefKind.None : refKinds[i]); - } - - // if we are given Void type the method returns Void, otherwise its return type is the last type parameter of the delegate: - var returnType = TypeWithAnnotations.Create(voidReturnTypeOpt ?? typeParams[parameterCount]); - var returnRefKind = (refKinds.IsNull || voidReturnTypeOpt is { }) ? RefKind.None : refKinds[parameterCount]; - - var method = new SynthesizedDelegateInvokeMethod(containingType, parameterTypes, parameterRefKinds, returnType, returnRefKind); - parameterRefKinds.Free(); - parameterTypes.Free(); - return method; - } - } - - public override Symbol ContainingSymbol - { - get { return _containingSymbol; } - } - - public override TypeKind TypeKind - { - get { return TypeKind.Delegate; } - } - - internal override MethodSymbol Constructor - { - get { return _constructor; } - } - - public override IEnumerable MemberNames - { - get { return new[] { _constructor.Name, _invoke.Name }; } - } - - public override ImmutableArray GetMembers() - { - return ImmutableArray.Create(_constructor, _invoke); - } - - public override ImmutableArray GetMembers(string name) - { - return - (name == _constructor.Name) ? ImmutableArray.Create(_constructor) : - (name == _invoke.Name) ? ImmutableArray.Create(_invoke) : - ImmutableArray.Empty; - } - - public override Accessibility DeclaredAccessibility - { - get { return Accessibility.Internal; } - } - - public override bool IsSealed - { - get { return true; } - } - - internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics - => ContainingAssembly.GetSpecialType(SpecialType.System_MulticastDelegate); - - public sealed override bool AreLocalsZeroed - { - get { throw ExceptionUtilities.Unreachable; } - } - - internal override bool IsRecord => false; - internal override bool IsRecordStruct => false; - internal override bool HasPossibleWellKnownCloneMethod() => false; - } - internal sealed class SynthesizedDelegateConstructor : SynthesizedInstanceConstructor { private readonly ImmutableArray _parameters; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs index e9112667d293c..883dc136b4cfc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs @@ -29,9 +29,9 @@ public SynthesizedParameterSymbolBase( string name, bool isNullChecked) { - RoslynDebug.Assert(type.HasType); - RoslynDebug.Assert(name != null); - RoslynDebug.Assert(ordinal >= 0); + Debug.Assert(type.HasType); + Debug.Assert(name != null); + Debug.Assert(ordinal >= 0); _container = container; _type = type; diff --git a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs index 382394d4b4f29..65ccbac349bc6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs @@ -447,7 +447,7 @@ internal static int IsTupleElementNameReserved(string name) return 0; } - return matchesCanonicalElementName(name); + return MatchesCanonicalTupleElementName(name); static bool isElementNameForbidden(string name) { @@ -465,25 +465,25 @@ static bool isElementNameForbidden(string name) return false; } } + } - // Returns 3 for "Item3". - // Returns -1 otherwise. - static int matchesCanonicalElementName(string name) + // Returns 3 for "Item3". + // Returns -1 otherwise. + internal static int MatchesCanonicalTupleElementName(string name) + { + if (name.StartsWith("Item", StringComparison.Ordinal)) { - if (name.StartsWith("Item", StringComparison.Ordinal)) + string tail = name.Substring("Item".Length); + if (int.TryParse(tail, out int number)) { - string tail = name.Substring(4); - if (int.TryParse(tail, out int number)) + if (number > 0 && string.Equals(name, TupleMemberName(number), StringComparison.Ordinal)) { - if (number > 0 && string.Equals(name, TupleMemberName(number), StringComparison.Ordinal)) - { - return number; - } + return number; } } - - return -1; } + + return -1; } /// @@ -567,36 +567,6 @@ public sealed override ImmutableArray TupleElementTypesWith public sealed override ImmutableArray TupleElements => IsTupleType ? TupleData!.TupleElements(this) : default; - /// - /// For tuple fields that aren't TupleElementFieldSymbol or TupleErrorFieldSymbol, we cache their tuple element index. - /// This supports . - /// For those fields, we map from their definition to an index. - /// - public SmallDictionary? TupleFieldDefinitionsToIndexMap - { - get - { - if (!IsTupleType) - { - return null; - } - - if (!IsDefinition) - { - return this.OriginalDefinition.TupleFieldDefinitionsToIndexMap; - } - - return TupleData!.GetFieldDefinitionsToIndexMap(this); - } - } - - public virtual void InitializeTupleFieldDefinitionsToIndexMap() - { - Debug.Assert(this.IsTupleType); - Debug.Assert(this.IsDefinition); // we only store a map for definitions - _ = this.GetMembers(); - } - public TMember? GetTupleMemberSymbolForUnderlyingMember(TMember? underlyingMemberOpt) where TMember : Symbol { return IsTupleType ? TupleData!.GetTupleMemberSymbolForUnderlyingMember(underlyingMemberOpt) : null; @@ -611,10 +581,6 @@ protected ArrayBuilder MakeSynthesizedTupleMembers(ImmutableArray.GetInstance(elementTypes.Length, fillWithValue: false); var members = ArrayBuilder.GetInstance(currentMembers.Length); - // For tuple fields that aren't TupleElementFieldSymbol or TupleErrorFieldSymbol, we cache/map their tuple element index - // corresponding to their definition. We only need to do that for the definition of ValueTuple types. - var fieldDefinitionsToIndexMap = IsDefinition ? new SmallDictionary(ReferenceEqualityComparer.Instance) : null; - NamedTypeSymbol currentValueTuple = this; int currentNestingLevel = 0; @@ -692,7 +658,6 @@ protected ArrayBuilder MakeSynthesizedTupleMembers(ImmutableArray MakeSynthesizedTupleMembers(ImmutableArray members, for (int i = 0; i < fieldsPerType; i++) { WellKnownMember wellKnownTupleField = GetTupleTypeMember(arity, i + 1); - fieldsForElements.Add((FieldSymbol?)GetWellKnownMemberInType(members, wellKnownTupleField)); + fieldsForElements.Add((FieldSymbol?)getWellKnownMemberInType(members, wellKnownTupleField)); } } - static Symbol? GetWellKnownMemberInType(ImmutableArray members, WellKnownMember relativeMember) + static Symbol? getWellKnownMemberInType(ImmutableArray members, WellKnownMember relativeMember) { Debug.Assert(relativeMember >= WellKnownMember.System_ValueTuple_T1__Item1 && relativeMember <= WellKnownMember.System_ValueTuple_TRest__ctor); @@ -954,13 +915,6 @@ internal sealed class TupleExtraData private ImmutableArray _lazyDefaultElementFields; - /// - /// For tuple fields that aren't TupleElementFieldSymbol or TupleErrorFieldSymbol, we cache their tuple element index. - /// This supports . - /// For those fields, we map from their definition to an index. - /// - private SmallDictionary? _lazyFieldDefinitionsToIndexMap; - private SmallDictionary? _lazyUnderlyingDefinitionToMemberMap; /// @@ -1093,26 +1047,6 @@ ImmutableArray collectTupleElementFields(NamedTypeSymbol tuple) } } - internal SmallDictionary GetFieldDefinitionsToIndexMap(NamedTypeSymbol tuple) - { - Debug.Assert(tuple.IsTupleType); - Debug.Assert(tuple.IsDefinition); // we only store a map for definitions - if (_lazyFieldDefinitionsToIndexMap is null) - { - tuple.InitializeTupleFieldDefinitionsToIndexMap(); - } - - Debug.Assert(_lazyFieldDefinitionsToIndexMap is object); - return _lazyFieldDefinitionsToIndexMap; - } - - internal void SetFieldDefinitionsToIndexMap(SmallDictionary map) - { - Debug.Assert(map.Keys.All(k => k.IsDefinition)); - Debug.Assert(map.Values.All(v => v >= 0)); - Interlocked.CompareExchange(ref _lazyFieldDefinitionsToIndexMap, map, null); - } - internal SmallDictionary UnderlyingDefinitionToMemberMap { get diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs index 0d112e6ddfcea..c18c9b8683344 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedParameterSymbol.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; @@ -78,7 +76,7 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r _underlyingParameter.AddSynthesizedAttributes(moduleBuilder, ref attributes); } - internal sealed override ConstantValue ExplicitDefaultConstantValue + internal sealed override ConstantValue? ExplicitDefaultConstantValue { get { return _underlyingParameter.ExplicitDefaultConstantValue; } } @@ -118,7 +116,7 @@ public override ImmutableArray RefCustomModifiers get { return _underlyingParameter.RefCustomModifiers; } } - internal override MarshalPseudoCustomAttributeData MarshallingInformation + internal override MarshalPseudoCustomAttributeData? MarshallingInformation { get { return _underlyingParameter.MarshallingInformation; } } @@ -149,7 +147,7 @@ internal override ImmutableHashSet NotNullIfParameterNotNull get { return _underlyingParameter.NotNullIfParameterNotNull; } } - public override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default) + public override string GetDocumentationCommentXml(CultureInfo? preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default) { return _underlyingParameter.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken); } diff --git a/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.ParsedSyntaxTree.cs b/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.ParsedSyntaxTree.cs index 5ef6e809a2953..3fff5bd7af407 100644 --- a/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.ParsedSyntaxTree.cs +++ b/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.ParsedSyntaxTree.cs @@ -32,7 +32,7 @@ internal ParsedSyntaxTree( SourceText? textOpt, Encoding? encodingOpt, SourceHashAlgorithm checksumAlgorithm, - string path, + string? path, CSharpParseOptions options, CSharpSyntaxNode root, Syntax.InternalSyntax.DirectiveStack directives, diff --git a/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.cs b/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.cs index 4f15d219b8fa6..6a6b48dbe3346 100644 --- a/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.cs +++ b/src/Compilers/CSharp/Portable/Syntax/CSharpSyntaxTree.cs @@ -311,7 +311,7 @@ private void BuildPreprocessorStateChangeMap() /// /// Creates a new syntax tree from a syntax node. /// - public static SyntaxTree Create(CSharpSyntaxNode root, CSharpParseOptions? options = null, string path = "", Encoding? encoding = null) + public static SyntaxTree Create(CSharpSyntaxNode root, CSharpParseOptions? options = null, string? path = "", Encoding? encoding = null) { #pragma warning disable CS0618 // We are calling into the obsolete member as that's the one that still does the real work return Create(root, options, path, encoding, diagnosticOptions: null); @@ -330,7 +330,7 @@ public static SyntaxTree Create(CSharpSyntaxNode root, CSharpParseOptions? optio public static SyntaxTree Create( CSharpSyntaxNode root, CSharpParseOptions? options, - string path, + string? path, Encoding? encoding, // obsolete parameter -- unused ImmutableDictionary? diagnosticOptions, @@ -927,7 +927,7 @@ public static SyntaxTree ParseText( public static SyntaxTree Create( CSharpSyntaxNode root, CSharpParseOptions? options, - string path, + string? path, Encoding? encoding, ImmutableDictionary? diagnosticOptions) => Create(root, options, path, encoding, diagnosticOptions, isGeneratedCode: null); diff --git a/src/Compilers/CSharp/Portable/Syntax/ConstructorDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/ConstructorDeclarationSyntax.cs index bc5f77fa7fd0d..324e4a1967b4d 100644 --- a/src/Compilers/CSharp/Portable/Syntax/ConstructorDeclarationSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/ConstructorDeclarationSyntax.cs @@ -39,7 +39,7 @@ public static ConstructorDeclarationSyntax ConstructorDeclaration( SyntaxTokenList modifiers, SyntaxToken identifier, ParameterListSyntax parameterList, - ConstructorInitializerSyntax initializer, + ConstructorInitializerSyntax? initializer, BlockSyntax body) => ConstructorDeclaration( attributeLists, @@ -56,8 +56,8 @@ public static ConstructorDeclarationSyntax ConstructorDeclaration( SyntaxTokenList modifiers, SyntaxToken identifier, ParameterListSyntax parameterList, - ConstructorInitializerSyntax initializer, - BlockSyntax body, + ConstructorInitializerSyntax? initializer, + BlockSyntax? body, SyntaxToken semicolonToken) => ConstructorDeclaration( attributeLists, diff --git a/src/Compilers/CSharp/Portable/Syntax/DestructorDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/DestructorDeclarationSyntax.cs index b6a1ffc1ec00e..4140104da4b4c 100644 --- a/src/Compilers/CSharp/Portable/Syntax/DestructorDeclarationSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/DestructorDeclarationSyntax.cs @@ -56,7 +56,7 @@ public static DestructorDeclarationSyntax DestructorDeclaration( SyntaxToken tildeToken, SyntaxToken identifier, ParameterListSyntax parameterList, - BlockSyntax body, + BlockSyntax? body, SyntaxToken semicolonToken) => DestructorDeclaration( attributeLists, diff --git a/src/Compilers/CSharp/Portable/Syntax/IndexerDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/IndexerDeclarationSyntax.cs index c87269a9fe8bc..783602f0ffd65 100644 --- a/src/Compilers/CSharp/Portable/Syntax/IndexerDeclarationSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/IndexerDeclarationSyntax.cs @@ -37,9 +37,9 @@ public static IndexerDeclarationSyntax IndexerDeclaration( SyntaxList attributeLists, SyntaxTokenList modifiers, TypeSyntax type, - ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifier, + ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, BracketedParameterListSyntax parameterList, - AccessorListSyntax accessorList) + AccessorListSyntax? accessorList) { return SyntaxFactory.IndexerDeclaration( attributeLists: attributeLists, diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxFactory.cs index 1a73210aab6ba..20ea4a09e622c 100644 --- a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/SyntaxFactory.cs @@ -124,6 +124,14 @@ internal static SyntaxToken Token(GreenNode leading, SyntaxKind kind, GreenNode return SyntaxToken.Create(kind, leading, trailing); } + /// + /// Creates a token whose and are the same. + /// + internal static SyntaxToken Token(GreenNode leading, SyntaxKind kind, string text, GreenNode trailing) + { + return Token(leading, kind, text, text, trailing); + } + internal static SyntaxToken Token(GreenNode leading, SyntaxKind kind, string text, string valueText, GreenNode trailing) { Debug.Assert(SyntaxFacts.IsAnyToken(kind)); diff --git a/src/Compilers/CSharp/Portable/Syntax/InterpolatedStringExpressionSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/InterpolatedStringExpressionSyntax.cs new file mode 100644 index 0000000000000..cc6bef2d0194f --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/InterpolatedStringExpressionSyntax.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 Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp +{ + public partial class SyntaxFactory + { + public static InterpolatedStringExpressionSyntax InterpolatedStringExpression(SyntaxToken stringStartToken) + => InterpolatedStringExpression(stringStartToken, Token(SyntaxKind.InterpolatedStringEndToken)); + + public static InterpolatedStringExpressionSyntax InterpolatedStringExpression(SyntaxToken stringStartToken, SyntaxList contents) + => InterpolatedStringExpression(stringStartToken, contents, Token(SyntaxKind.InterpolatedStringEndToken)); + } +} diff --git a/src/Compilers/CSharp/Portable/Syntax/LiteralExpressionSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/LiteralExpressionSyntax.cs new file mode 100644 index 0000000000000..fe09c3938a4eb --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/LiteralExpressionSyntax.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 Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp +{ + public partial class SyntaxFactory + { + /// Creates a new LiteralExpressionSyntax instance. + public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind) + => SyntaxFactory.LiteralExpression(kind, SyntaxFactory.Token(GetLiteralExpressionTokenKind(kind))); + + private static SyntaxKind GetLiteralExpressionTokenKind(SyntaxKind kind) + => kind switch + { + SyntaxKind.ArgListExpression => SyntaxKind.ArgListKeyword, + SyntaxKind.NumericLiteralExpression => SyntaxKind.NumericLiteralToken, + SyntaxKind.StringLiteralExpression => SyntaxKind.StringLiteralToken, + SyntaxKind.CharacterLiteralExpression => SyntaxKind.CharacterLiteralToken, + SyntaxKind.TrueLiteralExpression => SyntaxKind.TrueKeyword, + SyntaxKind.FalseLiteralExpression => SyntaxKind.FalseKeyword, + SyntaxKind.NullLiteralExpression => SyntaxKind.NullKeyword, + SyntaxKind.DefaultLiteralExpression => SyntaxKind.DefaultKeyword, + _ => throw new ArgumentOutOfRangeException(), + }; + } +} diff --git a/src/Compilers/CSharp/Portable/Syntax/LocalFunctionStatementSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/LocalFunctionStatementSyntax.cs index be7e4cfc5ac64..4cb9a352a0052 100644 --- a/src/Compilers/CSharp/Portable/Syntax/LocalFunctionStatementSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/LocalFunctionStatementSyntax.cs @@ -21,13 +21,13 @@ namespace Microsoft.CodeAnalysis.CSharp public partial class SyntaxFactory { // Preserved as shipped public API for binary compatibility - public static LocalFunctionStatementSyntax LocalFunctionStatement(SyntaxTokenList modifiers, TypeSyntax returnType, SyntaxToken identifier, TypeParameterListSyntax typeParameterList, ParameterListSyntax parameterList, SyntaxList constraintClauses, BlockSyntax body, ArrowExpressionClauseSyntax expressionBody) + public static LocalFunctionStatementSyntax LocalFunctionStatement(SyntaxTokenList modifiers, TypeSyntax returnType, SyntaxToken identifier, TypeParameterListSyntax? typeParameterList, ParameterListSyntax parameterList, SyntaxList constraintClauses, BlockSyntax? body, ArrowExpressionClauseSyntax? expressionBody) { return LocalFunctionStatement(attributeLists: default, modifiers, returnType, identifier, typeParameterList, parameterList, constraintClauses, body, expressionBody, semicolonToken: default); } // Preserved as shipped public API for binary compatibility - public static LocalFunctionStatementSyntax LocalFunctionStatement(SyntaxTokenList modifiers, TypeSyntax returnType, SyntaxToken identifier, TypeParameterListSyntax typeParameterList, ParameterListSyntax parameterList, SyntaxList constraintClauses, BlockSyntax body, ArrowExpressionClauseSyntax expressionBody, SyntaxToken semicolonToken) + public static LocalFunctionStatementSyntax LocalFunctionStatement(SyntaxTokenList modifiers, TypeSyntax returnType, SyntaxToken identifier, TypeParameterListSyntax? typeParameterList, ParameterListSyntax parameterList, SyntaxList constraintClauses, BlockSyntax? body, ArrowExpressionClauseSyntax? expressionBody, SyntaxToken semicolonToken) { return LocalFunctionStatement(attributeLists: default, modifiers, returnType, identifier, typeParameterList, parameterList, constraintClauses, body, expressionBody, semicolonToken); } diff --git a/src/Compilers/CSharp/Portable/Syntax/ParameterSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/ParameterSyntax.cs index 8097295cb2fe1..cc15e1bd6bcdd 100644 --- a/src/Compilers/CSharp/Portable/Syntax/ParameterSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/ParameterSyntax.cs @@ -2,10 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; - namespace Microsoft.CodeAnalysis.CSharp.Syntax { public partial class ParameterSyntax @@ -20,7 +16,7 @@ internal bool IsArgList public ParameterSyntax Update(SyntaxList attributeLists, SyntaxTokenList modifiers, TypeSyntax type, SyntaxToken identifier, EqualsValueClauseSyntax @default) { - return Update(attributeLists, modifiers, type, identifier, exclamationExclamationToken: default, @default); + return Update(attributeLists, modifiers, type, identifier, exclamationExclamationToken: ExclamationExclamationToken, @default); } } } diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index 4aebdf0ee086d..5e3e42fb8337a 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -874,6 +874,8 @@ + + @@ -1938,8 +1940,10 @@ + + - The first part of an interpolated string, $" or $@" + The first part of an interpolated string, $" or $@" or $""" @@ -1949,6 +1953,9 @@ + + + The closing quote of the interpolated string. @@ -2143,12 +2150,20 @@ + + This could be a single { or multiple in a row (in the case of an interpolation in a raw interpolated string). + + + + This could be a single } or multiple in a row (in the case of an interpolation in a raw interpolated string). + + diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs index 0899313520fb4..a4767457a66e5 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs @@ -82,6 +82,8 @@ private static bool AreTokensEquivalent(GreenNode? before, GreenNode? after, Fun case SyntaxKind.NumericLiteralToken: case SyntaxKind.CharacterLiteralToken: case SyntaxKind.StringLiteralToken: + case SyntaxKind.SingleLineRawStringLiteralToken: + case SyntaxKind.MultiLineRawStringLiteralToken: case SyntaxKind.InterpolatedStringTextToken: if (((Green.SyntaxToken)before).Text != ((Green.SyntaxToken)after).Text) { diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index e376a328ebd23..c82a0bbc87ce6 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -314,8 +314,8 @@ public static SyntaxToken Identifier(SyntaxTriviaList leading, string text, Synt /// Creates a verbatim token with kind IdentifierToken containing the specified text. /// /// A list of trivia immediately preceding the token. - /// The raw text of the identifier name, including any escapes or leading '@' - /// character as it is in source. + /// The identifier, not including any escapes or leading '@' + /// character. /// The canonical value of the token's text. /// A list of trivia immediately following the token. public static SyntaxToken VerbatimIdentifier(SyntaxTriviaList leading, string text, string valueText, SyntaxTriviaList trailing) @@ -2434,7 +2434,7 @@ public static PropertyDeclarationSyntax PropertyDeclaration( SyntaxList attributeLists, SyntaxTokenList modifiers, TypeSyntax type, - ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifier, + ExplicitInterfaceSpecifierSyntax? explicitInterfaceSpecifier, SyntaxToken identifier, AccessorListSyntax accessorList) { @@ -2456,7 +2456,7 @@ public static ConversionOperatorDeclarationSyntax ConversionOperatorDeclaration( SyntaxToken operatorKeyword, TypeSyntax type, ParameterListSyntax parameterList, - BlockSyntax body, + BlockSyntax? body, SyntaxToken semicolonToken) { return SyntaxFactory.ConversionOperatorDeclaration( @@ -2522,7 +2522,7 @@ public static OperatorDeclarationSyntax OperatorDeclaration( SyntaxToken operatorKeyword, SyntaxToken operatorToken, ParameterListSyntax parameterList, - BlockSyntax body, + BlockSyntax? body, SyntaxToken semicolonToken) { return SyntaxFactory.OperatorDeclaration( @@ -2615,7 +2615,7 @@ public static AccessorDeclarationSyntax AccessorDeclaration(SyntaxKind kind, Syn public static AccessorDeclarationSyntax AccessorDeclaration(SyntaxKind kind, SyntaxList attributeLists, SyntaxTokenList modifiers, SyntaxToken keyword, ArrowExpressionClauseSyntax expressionBody, SyntaxToken semicolonToken) => SyntaxFactory.AccessorDeclaration(kind, attributeLists, modifiers, keyword, body: null, expressionBody, semicolonToken); - public static EnumMemberDeclarationSyntax EnumMemberDeclaration(SyntaxList attributeLists, SyntaxToken identifier, EqualsValueClauseSyntax equalsValue) + public static EnumMemberDeclarationSyntax EnumMemberDeclaration(SyntaxList attributeLists, SyntaxToken identifier, EqualsValueClauseSyntax? equalsValue) => EnumMemberDeclaration(attributeLists, modifiers: default, identifier, equalsValue); diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index ad1ac640a2e05..775b8d38284fe 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -487,8 +487,10 @@ public enum SyntaxKind : ushort XmlTextLiteralToken = 8513, // xml text node text XmlTextLiteralNewLineToken = 8514, - InterpolatedStringToken = 8515, // terminal for a whole interpolated string $" ... { expr } ..." - // This only exists in transient form during parsing. + /// + /// Token for a whole interpolated string $""" ... { expr } ...""". This only exists in transient form during parsing. + /// + InterpolatedStringToken = 8515, InterpolatedStringTextToken = 8517, // literal text that is part of an interpolated string // trivia @@ -870,5 +872,12 @@ public enum SyntaxKind : ushort ExpressionColon = 9069, LineDirectivePosition = 9070, LineSpanDirectiveTrivia = 9071, + + SingleLineRawStringLiteralToken = 9072, + MultiLineRawStringLiteralToken = 9073, + + InterpolatedSingleLineRawStringStartToken = 9080, // $""" + InterpolatedMultiLineRawStringStartToken = 9081, // $""" (whitespace and newline are included in the Text for this token) + InterpolatedRawStringEndToken = 9082, // """ (preceding whitespace and newline are included in the Text for this token) } } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs index a5edff8780b64..ca02f909eb2d2 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -181,12 +181,13 @@ internal static bool IsLiteral(SyntaxKind kind) { case SyntaxKind.IdentifierToken: case SyntaxKind.StringLiteralToken: + case SyntaxKind.SingleLineRawStringLiteralToken: + case SyntaxKind.MultiLineRawStringLiteralToken: case SyntaxKind.CharacterLiteralToken: case SyntaxKind.NumericLiteralToken: case SyntaxKind.XmlTextLiteralToken: case SyntaxKind.XmlTextLiteralNewLineToken: case SyntaxKind.XmlEntityLiteralToken: - //case SyntaxKind.Unknown: return true; default: return false; @@ -201,12 +202,17 @@ public static bool IsAnyToken(SyntaxKind kind) case SyntaxKind.InterpolatedStringToken: case SyntaxKind.InterpolatedStringStartToken: case SyntaxKind.InterpolatedVerbatimStringStartToken: + case SyntaxKind.InterpolatedMultiLineRawStringStartToken: + case SyntaxKind.InterpolatedSingleLineRawStringStartToken: case SyntaxKind.InterpolatedStringTextToken: case SyntaxKind.InterpolatedStringEndToken: + case SyntaxKind.InterpolatedRawStringEndToken: case SyntaxKind.LoadKeyword: case SyntaxKind.NullableKeyword: case SyntaxKind.EnableKeyword: case SyntaxKind.UnderscoreToken: + case SyntaxKind.MultiLineRawStringLiteralToken: + case SyntaxKind.SingleLineRawStringLiteralToken: return true; default: return false; @@ -530,25 +536,19 @@ public static bool IsLiteralExpression(SyntaxKind token) public static SyntaxKind GetLiteralExpression(SyntaxKind token) { - switch (token) + return token switch { - case SyntaxKind.StringLiteralToken: - return SyntaxKind.StringLiteralExpression; - case SyntaxKind.CharacterLiteralToken: - return SyntaxKind.CharacterLiteralExpression; - case SyntaxKind.NumericLiteralToken: - return SyntaxKind.NumericLiteralExpression; - case SyntaxKind.NullKeyword: - return SyntaxKind.NullLiteralExpression; - case SyntaxKind.TrueKeyword: - return SyntaxKind.TrueLiteralExpression; - case SyntaxKind.FalseKeyword: - return SyntaxKind.FalseLiteralExpression; - case SyntaxKind.ArgListKeyword: - return SyntaxKind.ArgListExpression; - default: - return SyntaxKind.None; - } + SyntaxKind.StringLiteralToken => SyntaxKind.StringLiteralExpression, + SyntaxKind.SingleLineRawStringLiteralToken => SyntaxKind.StringLiteralExpression, + SyntaxKind.MultiLineRawStringLiteralToken => SyntaxKind.StringLiteralExpression, + SyntaxKind.CharacterLiteralToken => SyntaxKind.CharacterLiteralExpression, + SyntaxKind.NumericLiteralToken => SyntaxKind.NumericLiteralExpression, + SyntaxKind.NullKeyword => SyntaxKind.NullLiteralExpression, + SyntaxKind.TrueKeyword => SyntaxKind.TrueLiteralExpression, + SyntaxKind.FalseKeyword => SyntaxKind.FalseLiteralExpression, + SyntaxKind.ArgListKeyword => SyntaxKind.ArgListExpression, + _ => SyntaxKind.None, + }; } public static bool IsInstanceExpression(SyntaxKind token) diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs index 11e4d3eefbd11..c38a56fce2aef 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs @@ -845,6 +845,13 @@ private static bool NeedsSeparator(SyntaxToken token, SyntaxToken next) return true; } + switch (token.Parent.Kind(), next.Parent.Kind()) + { + case (SyntaxKind.LineSpanDirectiveTrivia, SyntaxKind.LineDirectivePosition): + case (SyntaxKind.LineDirectivePosition, SyntaxKind.LineSpanDirectiveTrivia): + return true; + } + return false; } diff --git a/src/Compilers/CSharp/Portable/Syntax/TryStatementSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/TryStatementSyntax.cs index ff95cd467ee33..9f3012ba122f9 100644 --- a/src/Compilers/CSharp/Portable/Syntax/TryStatementSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/TryStatementSyntax.cs @@ -17,10 +17,10 @@ namespace Microsoft.CodeAnalysis.CSharp { public partial class SyntaxFactory { - public static TryStatementSyntax TryStatement(BlockSyntax block, SyntaxList catches, FinallyClauseSyntax @finally) + public static TryStatementSyntax TryStatement(BlockSyntax block, SyntaxList catches, FinallyClauseSyntax? @finally) => TryStatement(attributeLists: default, block, catches, @finally); - public static TryStatementSyntax TryStatement(SyntaxToken tryKeyword, BlockSyntax block, SyntaxList catches, FinallyClauseSyntax @finally) + public static TryStatementSyntax TryStatement(SyntaxToken tryKeyword, BlockSyntax block, SyntaxList catches, FinallyClauseSyntax? @finally) => TryStatement(attributeLists: default, tryKeyword, block, catches, @finally); } } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index e2ff29ddddcc2..755b8ba84cac7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -34,7 +34,7 @@ '&' on method groups cannot be used in expression trees - & pro skupiny metod se nedá použít ve stromech výrazů. + '&' pro skupiny metod se nedá použít ve stromech výrazů. @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + {0} nejde nastavit tak, aby se povolovala hodnota null. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + V signatuře metody s atributem UnmanagedCallersOnly se nedají použít hodnoty ref, in ani out. @@ -357,6 +357,11 @@ Proměnná se nedá deklarovat ve vzoru not nebo or. + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. Tento vzor discard není povolený jako návěstí příkazu case v příkazu switch. Použijte „case var _:“ pro vzor discard nebo „case @_:“ pro konstantu s názvem „_“. @@ -407,6 +412,11 @@ Příkaz nemůže začínat na else. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Vstupní body aplikací nemůžou mít atribut UnmanagedCallersOnly. @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + Strom výrazů možná neobsahuje vzor přístupu indexeru System.Index nebo System.Range. @@ -597,6 +607,11 @@ Poziční člen {0}, který odpovídá tomuto parametru je skrytý. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context Operátor potlačení není v tomto kontextu povolený. @@ -632,11 +647,6 @@ Argumenty s modifikátorem in se nedají použít v dynamicky volaných výrazech. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. Dědění ze záznamu se zapečetěným objektem Object.ToString se v jazyce C# {0} nepodporuje. Použijte prosím jazykovou verzi {1} nebo vyšší. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + Převody interpolovaných obslužných rutin řetězců, které odkazují na indexovanou instanci, se nedají použít v inicializátorech členů indexeru. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + Kontextové klíčové slovo var se nedá použít jako explicitní návratový typ lambda. A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + Výraz lambda s atributy nejde převést na strom výrazu. + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - 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. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + Parametr {0} může mít v implementačních metodách pouze kontrolu hodnot null vykřičníku. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + V jazyce C# {0} se nové řádky uvnitř neliterálního interpolovaného řetězce nepodporují. Použijte prosím verzi jazyka {1} nebo novější. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + Parametr '{0}' je typ hodnoty, která nemůže mít hodnotu null, a nemůže mít zaškrtnutou hodnotu null. @@ -927,6 +947,16 @@ Konstruktor struktury bez parametrů musí být public. + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. {0} není instanční metoda. Přijímač nemůže být argumentem obslužné rutiny interpolovaného řetězce. @@ -937,9 +967,9 @@ {0} musí povolovat přepisování, protože obsahující záznam není zapečetěný. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ Dílčí vzor vlastnosti vyžaduje odkaz na vlastnost nebo pole k přiřazení, např. „{{ Name: {0} }}“. + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. Typ {0} nemůže být vložený, protože má reabstrakci člena ze základního rozhraní. Zvažte nastavení vlastnosti Vložit typy spolupráce na hodnotu false. @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + Konstruktor deklarovaný v „record struct“ se seznamem parametrů musí mít inicializátor „this“, který volá primární konstruktor nebo explicitně deklarovaný konstruktor. @@ -1222,9 +1272,14 @@ Zadal se argument stdin -, ale vstup se nepřesměroval na stream standardního vstupu. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + Položka „struct“ s inicializátory pole musí obsahovat explicitně deklarovaný konstruktor. @@ -1247,6 +1302,21 @@ Řídící výraz switch je nutné uzavřít do závorek. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. Příkazy nejvyšší úrovně se musí nacházet před obory názvů a deklaracemi typů. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + Vzory seznamů se nedají používat pro hodnotu typu {0}. Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + Vzory řezů se nedají používat pro hodnotu typu {0}. + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ návratový typ lambda - - length pattern - length pattern - - line span directive direktiva line span @@ -1389,12 +1459,12 @@ list pattern - list pattern + vzor seznamu newlines in interpolations - newlines in interpolations + nové řádky v interpolacích @@ -1407,6 +1477,11 @@ pozice polí v záznamech + + raw string literals + raw string literals + + record structs struktury záznamů @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + kontrola hodnoty null parametru @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + Operace může při běhu přetéct {0} (pro přepis použijte syntaxi unchecked) The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + Operace může při běhu přetéct (pro přepis použijte syntaxi unchecked) @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + Název typu {0} obsahuje jenom malá písmena ASCII. Tyto názvy se můžou stát vyhrazenými pro daný jazyk. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + Název typu obsahuje jenom malá písmena ASCII. Tyto názvy se můžou stát vyhrazenými pro daný jazyk. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + Převádí se skupina metod {0} na nedelegující typ {1}. Chtěli jste volat tuto metodu? Converting method group to non-delegate type - Converting method group to non-delegate type + Převádí se skupina metod na nedelegující typ. Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + Parametr {0} má hodnotu null, ale ve výchozím nastavení je null. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + Parametr má hodnotu null, ale ve výchozím nastavení je null. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + Typ {0} s možnou hodnotou null je zaškrtnut hodnotou null a vyvolá se při hodnotě null. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + Typ s možnou hodnotou null je zaškrtnut hodnotou null a vyvolá se při hodnotě null. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - Parametr {0} se v seznamu parametrů nachází za {1}, ale používá se jako argument pro převody obslužných rutin interpolovaných řetězců. To vyžaduje, aby volající změnil pořadí parametrů s pojmenovanými argumenty na lokalitě volání. Doporučujeme, abyste parametr obslužné rutiny interpolovaného řetězce vložili za všechny ostatní zahrnuté argumenty. + Parametr {0} se v seznamu parametrů nachází za {1}, ale používá se jako argument pro převody obslužných rutin interpolovaných řetězců. To vyžaduje, aby volající změnil pořadí parametrů s pojmenovanými argumenty na lokalitě volání. Doporučujeme, abyste parametr obslužné rutiny interpolovaného řetězce vložili za všechny ostatní zahrnuté argumenty. @@ -3648,7 +3723,7 @@ The character '<' cannot be used in an attribute value. - Znak < se nedá použít v hodnotě atributu. + Znak '<' se nedá použít v hodnotě atributu. @@ -3703,7 +3778,7 @@ The literal string ']]>' is not allowed in element content. - V obsahu elementu není povolený řetězec literálu ]]>. + V obsahu elementu není povolený řetězec literálu ']]>'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index f298ae69df379..c8d2a36b20faa 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + "{0}" kann keine NULL-Werte zulassen. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + „ref“, „in“ und „out“ können nicht in der Signatur einer Methode verwendet werden, die mit „UnmanagedCallersOnly“ attributiert ist. @@ -357,6 +357,11 @@ Eine Variable darf nicht innerhalb eines not- oder or-Musters deklariert werden. + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. Das discard-Muster ist als case-Bezeichnung in einer switch-Anweisung unzulässig. Verwenden Sie "case var _:" für ein discard-Muster oder "case @_:" für eine Konstante namens "_". @@ -407,6 +412,11 @@ Eine Anweisung kann nicht mit "else" beginnen. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Anwendungseinstiegspunkte können nicht mit dem Attribut "UnmanagedCallersOnly" versehen werden. @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + Eine Ausdrucksbaumstruktur darf keinen System.Index- oder System.Range-Musterindexerzugriff enthalten. @@ -597,6 +607,11 @@ Das für diesen Parameter gefundene positionelle Element „{0}“ ist ausgeblendet. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context Ein Unterdrückungsoperator ist in diesem Kontext unzulässig. @@ -632,11 +647,6 @@ Argumente mit dem Modifizierer "in" können nicht in dynamisch gebundenen Ausdrücken verwendet werden. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. Das Erben von einem Datensatz mit einem versiegelten "Object.ToString" wird in C# {0} nicht unterstützt. Verwenden Sie die Sprachversion "{1}" oder höher. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + Handler-Konvertierungen interpolierter Zeichenfolgen die auf die Instanz verweisen, die gerade indiziert wird, können nicht in Indexer-Member-Initialisierern verwendet werden. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + Das kontextbezogene Schlüsselwort „var“ kann nicht als expliziter Lambdarückgabetyp verwendet werden. A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + Ein Lambdaausdruck mit Attributen kann nicht in eine Ausdrucksbaumstruktur konvertiert werden. + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - 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. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + Der Parameter „{0}“ kann nur eine Ausrufezeichen-NULL-Überprüfung in den Implementierungsmethoden aufweisen. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + Zeilenumbrüche innerhalb einer nicht ausführlichen interpolierten Zeichenfolge werden in C#-{0} nicht unterstützt. Verwenden Sie die Sprachversion {1} oder höher. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + Der Parameter „{0}“ ist ein Non-Nullable-Werttyp und kann nicht auf NULL-Werte überprüft werden. @@ -927,6 +947,16 @@ Der parameterlose Strukturkonstruktor muss "public" sein. + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. „{0}“ ist keine Instanzmethode, der Empfänger kann kein Handlerargument einer interpolierten Zeichenfolge sein. @@ -937,9 +967,9 @@ "{0}" muss Überschreibungen zulassen, weil der enthaltende Datensatz nicht versiegelt ist. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ Ein Eigenschaftsteilmuster erfordert einen Verweis auf die abzugleichende Eigenschaft oder das abzugleichende Feld. Beispiel: "{{ Name: {0} }}" + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. Der Typ "{0}" kann nicht eingebettet werden, weil er eine Neuabstraktion eines Members aus der Basisschnittstelle aufweist. Legen Sie die Eigenschaft "Interoptypen einbetten" ggf. auf FALSE fest. @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + Ein in „record struct“ mit Parameterliste deklarierter Konstruktor muss über einen „this“-Initialisierer verfügen, der den primären Konstruktor oder einen explizit deklarierten Konstruktor aufruft. @@ -1222,9 +1272,14 @@ Das stdin-Argument "-" ist angegeben, aber die Eingabe wurde nicht vom Standardeingabestream umgeleitet. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + Eine „Struktur“ mit Feldinitialisierern muss einen explizit deklarierten Konstruktor enthalten. @@ -1247,6 +1302,21 @@ Der Ausdruck zur Steuerung von Schaltern muss in Klammern eingeschlossen werden. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. Anweisungen der obersten Ebene müssen vor Namespace- und Typdeklarationen stehen. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + Listenmuster dürfen nicht für einen Wert vom Typ „{0}“ verwendet werden. Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + Segmentmuster dürfen nicht für einen Wert vom Typ „{0}“ verwendet werden. + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ Lambda-Rückgabetyp - - length pattern - length pattern - - line span directive Zeilenabstand-Anweisung @@ -1389,12 +1459,12 @@ list pattern - list pattern + Listenmuster newlines in interpolations - newlines in interpolations + Zeilenumbrüche in Interpolationen @@ -1407,6 +1477,11 @@ Positionsfelder in Datensätzen + + raw string literals + raw string literals + + record structs Datensatzstrukturen @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + NULL-Überprüfung des Parameters @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + Der Vorgang kann zur Laufzeit einen Überlauf von „{0}“ verursachen (verwenden Sie zum Überschreiben die Syntax „unchecked“) The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + Der Vorgang kann zur Laufzeit überlaufen (verwenden Sie zum Überschreiben die Syntax „unchecked“) @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + Der Typname „{0}“ enthält nur ASCII-Zeichen in Kleinbuchstaben. Solche Namen können möglicherweise für die Sprache reserviert werden. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + Der Typname enthält nur ASCII-Zeichen in Kleinbuchstaben. Solche Namen können möglicherweise für die Sprache reserviert werden. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + Die Methodengruppe „{0}“ wird in den Nichtdelegattyp „{1}“ konvertiert. Wollten Sie die Methode aufrufen? Converting method group to non-delegate type - Converting method group to non-delegate type + Die Methodengruppe wird in einen Nichtdelegattyp konvertiert. Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + Der Parameter „{0}“ wurde auf NULL-Werte überprüft, ist aber standardmäßig NULL. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + Der Parameter wurde auf NULL-Werte überprüft, ist aber standardmäßig NULL. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + Der Nullable-Typ „{0}“ wurde auf NULL-Werte überprüft und wird bei NULL ausgelöst. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + Der Nullable-Typ wurde auf NULL-Werte überprüft und wird bei NULL ausgelöst. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - Der Parameter {0} tritt nach {1} in der Parameterliste auf, wird jedoch als Argument für die Handler-Konvertierungen einer interpolierten Zeichenfolge verwendet. Dies erfordert, dass der Aufrufer Parameter mit benannten Argumenten an der Aufrufsite neu anordnen kann. Erwägen Sie, den Handler-Parameter einer interpolierten Zeichenfolge hinter alle beteiligten Argumenten zu platzieren. + Der Parameter „{0}“ tritt nach „{1}“ in der Parameterliste auf, wird jedoch als Argument für die Handler-Konvertierungen einer interpolierten Zeichenfolge verwendet. Dies erfordert, dass der Aufrufer Parameter mit benannten Argumenten an der Aufrufsite neu anordnen kann. Erwägen Sie, den Handler-Parameter einer interpolierten Zeichenfolge hinter alle beteiligten Argumenten zu platzieren. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index cd891365c5719..2941ce9d53bf8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + 'No se puede hacer que '{0}' acepte valores NULL. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + No se puede usar "ref", "in" o "out" en la firma de un método atribuido con "UnmanagedCallersOnly". @@ -357,6 +357,11 @@ Una variable no puede declararse dentro de un patrón "not" u "or". + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. El patrón de descarte no se permite como etiqueta de caso en una instrucción switch. Use "case var _:" para un patrón de descarte o "case @_:" para una constante con el nombre '_'. @@ -407,6 +412,11 @@ “else” no puede iniciar una instrucción. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Los puntos de entrada de la aplicación no se pueden atribuir con "UnmanagedCallersOnly". @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + Un árbol de expresión no puede contener un patrón System.Index o un acceso a indizador System.Range. @@ -597,6 +607,11 @@ El miembro posicional '{0}' que se corresponde con este parámetro está oculto. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context No se permite el operador de supresión en este contexto. @@ -632,11 +647,6 @@ No se pueden usar argumentos con el modificador "in" en expresiones distribuidas dinámicamente. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. No se admite heredar desde un registro con 'Object.ToString' sellado en C# {0}. Utilice la versión de idioma '{1}' o superior. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + Las conversiones de controlador de cadenas interpoladas que hacen referencia a la instancia que se está indizando no se puede usar en inicializadores de miembros de indizador. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + La palabra clave contextual "var" no se puede utilizar como un tipo de retorno lambda explícito A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + Una expresión lambda con atributos no se puede convertir en un árbol de expresión + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - 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. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + El parámetro '{0}' solo puede tener una comprobación nula de signo de exclamación en los métodos de implementación. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + No se admiten líneas nuevas dentro de una cadena interpolada no textual en C# {0}. Utilice la versión de idioma {1} o superior. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + El parámetro '{0}' es un tipo de valor que no acepta valores NULL y no se puede comprobar con valores NULL. @@ -927,6 +947,16 @@ El constructor de struct sin parámetros debe ser "public". + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. "{0}" no es un método de instancia, el receptor no puede ser un argumento de controlador de cadena interpolada. @@ -937,9 +967,9 @@ "{0}" debe permitir la invalidación porque el registro contenedor no está sellado. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ El subpatrón de una propiedad requiere una referencia a la propiedad o al campo que debe coincidir; por ejemplo, "{{ Name: {0} }}" + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. El tipo "{0}" no se puede insertar porque tiene una reabstracción de un miembro de la interfaz base. Puede establecer la propiedad "Incrustar tipos de interoperabilidad" en false. @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + Un constructor declarado en un 'record struct' con lista de parámetros debe tener un inicializador 'this' que llame al constructor principal o a un constructor declarado explícitamente. @@ -1222,9 +1272,14 @@ Se ha especificado el argumento stdin "-", pero la entrada no se ha redirigido desde el flujo de entrada estándar. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + Un 'struct' con inicializadores de campo debe incluir un constructor declarado explícitamente. @@ -1247,6 +1302,21 @@ La expresión switch aplicable requiere paréntesis. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. Las instrucciones de nivel superior deben preceder a las declaraciones de espacio de nombres y de tipos. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + No se pueden utilizar patrones de lista para un valor de tipo "{0}". Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + No se pueden utilizar patrones de segmento para el valor de tipo "{0}". + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ tipo de valor devuelto de lambda - - length pattern - length pattern - - line span directive directiva de intervalo de línea @@ -1389,12 +1459,12 @@ list pattern - list pattern + patrón de lista newlines in interpolations - newlines in interpolations + Nuevas líneas en interpolaciones @@ -1407,6 +1477,11 @@ campos posicionales en registros + + raw string literals + raw string literals + + record structs registros @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + comprobación null de parámetro @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + La operación puede desbordar '{0}' en tiempo de ejecución (use la sintaxis "sin activar" para invalidar) The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + La operación puede desbordarse en tiempo de ejecución (use la sintaxis "sin activar" para invalidarla). @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + El nombre de tipo '{0}' solo contiene caracteres ASCII en minúsculas. Estos nombres pueden quedar reservados para el idioma. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + El nombre de tipo solo contiene caracteres ASCII en minúsculas. Estos nombres pueden reservarse para el idioma. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + Convirtiendo el grupo de métodos '{0}' al tipo no delegado '{1}'. ¿Pretendía invocar el método? Converting method group to non-delegate type - Converting method group to non-delegate type + Convirtiendo grupo de métodos a tipo no delegado Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + El parámetro '{0}' está marcado como null, pero es NULL de forma predeterminada. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + El parámetro está comprobado con valores NULL, pero es NULL de forma predeterminada. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + El tipo que acepta valores NULL '{0}' está activado como NULL y se iniciará si es NULL. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + El tipo que acepta valores NULL está activado con valor NULL y se iniciará si es null. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - El parámetro {0}se produce después de {1} en la lista de parámetros, pero se usa como argumento para conversiones de controlador de cadena interpolada. Esto requerirá que el autor de llamada reordene los parámetros con argumentos con nombre en el sitio de llamada. Considere la posibilidad de colocar el parámetro de controlador de cadena interpolada después de todos los argumentos implicados. + El parámetro "{0}" se produce después de "{1}" en la lista de parámetros, pero se usa como argumento para conversiones de controlador de cadena interpolada. Esto requerirá que el autor de llamada reordene los parámetros con argumentos con nombre en el sitio de llamada. Considere la posibilidad de colocar el parámetro de controlador de cadena interpolada después de todos los argumentos implicados. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 8e76e509495f0..331c9ad687036 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + '{0}' ne peut pas être null. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + Impossible d'utiliser 'ref', 'in' ou 'out' dans la signature d'une méthode attribuée avec 'UnmanagedCallersOnly'. @@ -357,6 +357,11 @@ Une variable ne peut pas être déclarée dans un modèle 'not' ou 'or'. + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. Le modèle d'abandon n'est pas autorisé en tant qu'étiquette case dans une instruction switch. Utilisez 'case var _:' pour un modèle d'abandon, ou 'case @_:' pour une constante nommée '_'. @@ -407,6 +412,11 @@ 'else' ne peut pas démarrer d'instruction. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Les points d'entrée d'application ne peuvent pas être attribués avec 'UnmanagedCallersOnly'. @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + Une arborescence de l'expression ne peut pas contenir de modèle d'accès à l'indexeur System.Index ou System.Range @@ -597,6 +607,11 @@ Le membre '{0}' positionnel trouvé correspondant à ce paramètre est masqué. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context L'opérateur de suppression n'est pas autorisé dans ce contexte @@ -632,11 +647,6 @@ Impossible d'utiliser les arguments avec le modificateur 'in' dans les expressions dispatchées dynamiquement. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. L’héritage d’un enregistrement avec un 'Object.ToString' scellé n’est pas pris en charge dans C# {0}. Veuillez utiliser la version linguistique '{1}' ou version supérieure. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + Les conversions de gestionnaires de chaînes interpolées qui font référence à l'instance en cours d'indexation ne peuvent pas être utilisées dans les initialiseurs de membres d'indexeur. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + Le mot clé contextuel 'var' ne peut pas être utilisé comme type de retour lambda explicite A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + Une expression lambda avec un corps d'instruction ne peut pas être convertie en arborescence de l'expression + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - 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. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + Le paramètre '{0}' peut uniquement avoir une vérification null de point d’exclamation dans les méthodes d’implémentation. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + Les nouvelles lignes à l'intérieur d'une chaîne interpolée non textuelle ne sont pas prises en charge en C# {0}. Veuillez utiliser la version linguistique {1} ou supérieure. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + Le paramètre '{0}' est un type valeur non nullable et ne peut pas faire l’objet d’une vérification de valeur Null. @@ -927,6 +947,16 @@ Le constructeur de structure sans paramètre doit être « public ». + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. « {0} » n’est pas une méthode d’instance, le récepteur ne peut pas être un argument de gestionnaire de chaîne interpolé. @@ -937,9 +967,9 @@ '{0}' doit autoriser la substitution, car l'enregistrement contenant n'est pas sealed. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ Un sous-modèle de propriété nécessite une correspondance de la référence à la propriété ou au champ. Exemple : '{{ Nom: {0} }}' + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. Impossible d'incorporer le type '{0}', car il a une nouvelle abstraction d'un membre de l'interface de base. Affectez la valeur false à la propriété 'Incorporer les types interop'. @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + Un constructeur déclaré dans un 'record struct' avec une liste de paramètres doit avoir un initialiseur 'this' qui appelle le constructeur principal ou un constructeur explicitement déclaré. @@ -1222,9 +1272,14 @@ L'argument stdin '-' est spécifié, mais l'entrée n'a pas été redirigée à partir du flux d'entrée standard. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + Un 'struct' avec des initialiseurs de champ doit inclure un constructeur explicitement déclaré. @@ -1247,6 +1302,21 @@ Des parenthèses sont obligatoires autour de l'expression régissant switch. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. Les instructions de niveau supérieur doivent précéder les déclarations d'espace de noms et de type. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + Les modèles de liste ne peuvent pas être utilisés pour une valeur de type '{0}'. Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + Les modèles de tranche ne peuvent pas être utilisés pour une valeur de type '{0}'. + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ type de retour lambda - - length pattern - length pattern - - line span directive directive de l’étendue de ligne @@ -1389,12 +1459,12 @@ list pattern - list pattern + modèle de liste newlines in interpolations - newlines in interpolations + sauts de ligne dans les interpolations @@ -1407,6 +1477,11 @@ champs positionnels dans les enregistrements + + raw string literals + raw string literals + + record structs structs d’enregistrement @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + vérification de la valeur null du paramètre @@ -1469,7 +1544,7 @@ The CallerArgumentExpressionAttribute applied to parameter '{0}' will have no effect. It is applied with an invalid parameter name. - The CallerArgumentExpressionAttribute applied to parameter '{0}' will have no effect. It is applied with an invalid parameter name. + Le CallerArgumentExpressionAttribute appliqué au paramètre « {0} » n’aura aucun effet. Il est appliqué avec un nom de paramètre non valide. @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + L'opération peut dépasser {0}' au moment de l'exécution (utilisez la syntaxe 'unchecked' pour passer outre). The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + L'opération peut déborder au moment de l'exécution (utilisez la syntaxe 'unchecked' pour passer outre). @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + Le nom de type '{0}' contient uniquement des caractères ascii en minuscules. De tels noms peuvent devenir réservés pour la langue. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + Le nom de type contient uniquement des caractères ascii en minuscules. De tels noms peuvent devenir réservés pour la langue. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + Impossible de convertir le groupe de méthodes '{0}' en type non-délégué '{1}'. Souhaitiez-vous appeler la méthode? Converting method group to non-delegate type - Converting method group to non-delegate type + Conversion d’un groupe de méthodes en type non-délégué Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + Le paramètre '{0}' a la valeur Null, mais est null par défaut. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + Le paramètre est contrôlé comme nul mais est nul par défaut. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + Le type nullable '{0}' a la valeur Null et lève la valeur null. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + Le type Nullable est activé pour null et lèvera si null. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - Le paramètre {0} se produit après {1} dans la liste de paramètres, mais est utilisé en tant qu’argument pour les conversions de gestionnaire de chaîne interpolées. Cela demande à l’appelant de réorganiser les paramètres avec des arguments nommés sur le site d’appel. Envisagez de placer le paramètre de gestionnaire de chaîne interpolé après tous les arguments concernés. + Le paramètre '{0}' apparaît après '{1}' dans la liste des paramètres, mais est utilisé comme argument pour les conversions de gestionnaires de chaînes interpolées. Cela nécessitera que l'appelant réorganise les paramètres avec des arguments nommés sur le site d'appel. Envisagez de placer le paramètre de gestionnaire de chaîne interpolé après tous les arguments impliqués. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index c47fb03ef21aa..57385541bca79 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + '{0}' non può essere reso nullable. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + Non è possibile usare 'ref', 'in' o 'out' nella firma di un metodo con attributo 'UnmanagedCallersOnly'. @@ -357,6 +357,11 @@ Non è possibile dichiarare una variabile all'interno di un criterio 'not' o 'or'. + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. Il criterio di rimozione non è consentito come etichetta case in un'istruzione switch. Usare 'case var _:' per un criterio di rimozione oppure 'case @_:' per una costante denominata '_'. @@ -407,6 +412,11 @@ Un'istruzione non può iniziare con 'else'. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Non è possibile aggiungere ai punti di ingresso dell'applicazione l'attributo 'UnmanagedCallersOnly'. @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + Un albero delle espressioni non può contenere un accesso a indicizzatore System.Index o System.Range di criterio @@ -597,6 +607,11 @@ Il membro posizionale '{0}' trovato e corrispondente a questo parametro è nascosto. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context L'operatore di eliminazione non è consentito in questo contesto @@ -632,11 +647,6 @@ Non è possibile usare argomenti con il modificatore 'in' nelle espressioni inviate in modo dinamico. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. L'ereditarietà da un record con un 'Object.ToString' di tipo sealed non è supportata in C# {0}. Usare la versione '{1}' o successiva del linguaggio. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + Le conversioni di gestori di stringhe interpolate che fanno riferimento all'istanza indicizzata non possono essere utilizzate negli inizializzatori di membri dell'indicizzatore. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + Non è possibile usare la parola chiave contestuale 'var' come tipo restituito dell’espressione lambda A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + Non è possibile convertire un'espressione lambda con attributi in un albero delle espressioni + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - 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. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + Il parametro '{0}' può avere solo un controllo Null punto esclamativo nei metodi di implementazione. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + Nuove linee all'interno di una stringa interpolata non verbatim non sono supportate in C# {0}. Usare la versione del linguaggio {1} o le versioni successive. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + Il parametro '{0}' è un tipo di valore che non ammette i valori Null e non può essere controllato Null. @@ -927,6 +947,16 @@ Il costruttore struct senza parametri deve essere 'public'. + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. '{0}' non è un metodo di istanza. Il ricevitore non può essere un argomento del gestore di stringhe interpolate. @@ -937,9 +967,9 @@ '{0}' deve consentire l'override perché il record contenitore non è sealed. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ Con un criterio secondario di proprietà è richiesto un riferimento alla proprietà o al campo da abbinare, ad esempio '{{ Name: {0} }}' + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. Non è possibile incorporare il tipo '{0}' perché contiene una nuova astrazione di un membro dell'interfaccia di base. Provare a impostare la proprietà 'Incorpora tipi di interoperabilità' su false. @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + Un costruttore dichiarato in uno “struct di record” con elenco di parametri deve avere un inizializzatore “this” che chiama il costruttore primario o un costruttore dichiarato in modo esplicito. @@ -1222,9 +1272,14 @@ è stato specificato l'argomento stdin '-', ma l'input non è stato reindirizzato dal flusso di input standard. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + Un elemento 'struct' con inizializzatori di campo deve includere un costruttore dichiarato in modo esplicito. @@ -1247,6 +1302,21 @@ L'espressione che gestisce lo switch deve essere racchiusa tra parentesi. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. Le istruzioni di primo livello devono precedere le dichiarazioni di tipo e di spazio dei nomi. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + Non è possibile usare i modelli di elenco per un valore di tipo '{0}'. Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + Non è possibile usare Seziona modelli per un valore di tipo '{0}'. + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ tipo restituito dell'espressione lambda - - length pattern - length pattern - - line span directive direttiva per intervallo di riga @@ -1389,12 +1459,12 @@ list pattern - list pattern + modello di elenco newlines in interpolations - newlines in interpolations + nuove linee nelle interpolazioni @@ -1407,6 +1477,11 @@ campi posizionali nei record + + raw string literals + raw string literals + + record structs struct di record @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + controllo Null parametro @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + Con l’operazione può verificarsi un overflow '{0} 'in fase di esecuzione. Usare la sintassi 'unchecked' per eseguire l'override The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + Con l’operazione può verificarsi un overflow in fase di esecuzione. Usare la sintassi 'unchecked' per eseguire l'override @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + Il nome del tipo '{0}' contiene solo caratteri ascii minuscoli. Tali nomi possono diventare riservati per la lingua. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + Il nome del tipo contiene solo caratteri ascii minuscoli. Tali nomi possono diventare riservati per la lingua. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + Conversione del gruppo di metodi '{0}' nel tipo non delegato '{1}'. Si intendeva richiamare il metodo? Converting method group to non-delegate type - Converting method group to non-delegate type + Conversione del gruppo di metodi in un tipo non delegato Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + Il parametro '{0}' è controllato Null ma è Null per impostazione predefinita. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + Il parametro è controllato Null ma è Null per impostazione predefinita. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + Il tipo nullable '{0}' è controllato Null e genererà un'eccezione se Null. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + Il tipo nullable è controllato Null e verrà generato se Null. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - Il parametro {0} è indicato dopo {1} nell'elenco dei parametri, ma viene usato come argomento per le conversioni del gestore di stringhe interpolate. Al chiamante verrà richiesto di riordinare i parametri con argomenti denominati nel sito di chiamata. Provare a inserire il parametro del gestore di stringhe interpolate dopo tutti gli argomenti interessati. + Il parametro '{0}' è indicato dopo '{1}' nell'elenco di parametri, ma viene usato come argomento per le conversioni del gestore di stringhe interpolate. Al chiamante verrà richiesto di riordinare i parametri con argomenti denominati nel sito di chiamata. Provare a inserire il parametro del gestore di stringhe interpolate dopo tutti gli argomenti interessati. @@ -2359,7 +2434,7 @@ <null> - <Null> + <null> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 056a11080142a..292a3e25224a3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + '{0}' は null 許容にすることはできません。 @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + "UnmanagedCallersOnly" の属性が設定されたメソッドのシグネチャでは、"ref"、"in"、または "out" を使用できません。 @@ -357,6 +357,11 @@ 'not' または 'or' パターンの中で変数を宣言することはできません。 + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. この破棄パターンは switch ステートメントの case ラベルとして許可されていません。破棄パターンに 'case var _:' を使用するか、'_' という定数に'case @_:' をご使用ください。 @@ -407,6 +412,11 @@ 'else' でステートメントを開始することはできません。 + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. アプリケーションのエントリ ポイントに 'UnmanagedCallersOnly' 属性を設定することはできません。 @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + 式ツリーに、System.Index または System.Range インデクサー アクセスのパターンを含めることはできません @@ -597,6 +607,11 @@ このパラメーターに対応する位置にあるメンバー '{0}' が非表示になっています。 + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context このコンテキストでは抑制演算子が許可されていません @@ -632,11 +647,6 @@ 'in' 修飾子を持つ引数を、動的ディスパッチされる式で使用することはできません。 - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. シールされた ' Object. ToString ' を含むレコードからの継承は、C# {0} ではサポートされていません。' {1} ' 以上の言語バージョンを使用してください。 @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + インデックス付けされているインスタンスを参照する補間された文字列ハンドラーの変換は、インデクサー メンバー初期化子では使用できません。 @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + コンテキスト キーワード "var" を明示的なラムダ戻り値の型として使用することはできません A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + 属性を含むラムダ式は、式ツリーに変換できません + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - Slice patterns may only be used once and directly inside a list pattern. + スライス パターンは、1 回限り、リスト パターン内で直接使用される可能性があります。 @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + パラメーター '{0}' には、実装メソッドで感嘆符 null チェックのみを指定できます。 @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + 非逐語的な補間された文字列内の改行は、C# {0} ではサポートされていません。{1} またはそれ以上の言語バージョンを使用してください。 @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + パラメーター '{0}' は null 非許容の値の型であるため、null チェックできません。 @@ -927,6 +947,16 @@ パラメーターなしの構造体コンストラクターは 'パブリック' でなければなりません。 + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. '{0}' はインスタンス メソッドではありません。レシーバーを、補間された文字列ハンドラー引数にすることはできません。 @@ -937,9 +967,9 @@ '{0}' ではオーバーライドを許可する必要があります。これが含まれているレコードが sealed ではないためです。 - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ プロパティ サブパターンには、一致させるプロパティまたはフィールドへの参照が必要です。例: '{{ Name: {0} }}' + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. 型 '{0}' には基底インターフェイスからのメンバーの再抽象化があるため、この型を埋め込むことはできません。'相互運用型の埋め込み' プロパティを false に設定することをご検討ください。 @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + パラメーター リストを含む "record struct" で宣言されたコンストラクターには、プライマリ コンストラクターまたは明示的に宣言されたコンストラクターを呼び出す "this" 初期化子が必要です。 @@ -1222,9 +1272,14 @@ stdin 引数 '-' が指定されていますが、入力が標準入力ストリームからリダイレクトされていません。 + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + フィールド初期化子を持つ 'struct' には、明示的に宣言されたコンストラクターを含める必要があります。 @@ -1247,6 +1302,21 @@ switch を制御する式の周囲にはかっこが必要です。 + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. トップレベルのステートメントは、名前空間および型の宣言の前にある必要があります。 @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + リスト パターンは、'{0}' 型の値に使用されない可能性があります。 Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + スライス パターンは、'{0}' 型の値に使用されない可能性があります。 + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ ラムダ戻り値の型 - - length pattern - length pattern - - line span directive line span ディレクティブ @@ -1389,12 +1459,12 @@ list pattern - list pattern + リスト パターン newlines in interpolations - newlines in interpolations + 補間における改行 @@ -1407,6 +1477,11 @@ レコード内の位置指定フィールド + + raw string literals + raw string literals + + record structs レコード構造体 @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + パラメーターの null チェック @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + 実行時に操作がオーバーフロー '{0}' する可能性があります (オーバーライドするには 'unchecked' 構文を使用してください) The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + 実行時に操作がオーバーフローする可能性があります (オーバーライドするには 'unchecked' 構文を使用してください) @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + 型名 '{0}' には、小文字の ASCII 文字のみが含まれています。このような名前は、プログラミング言語用に予約されている可能性があります。 The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + 型名には、小文字の ASCII 文字のみが含まれています。このような名前は、プログラミング言語用に予約されている可能性があります。 Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + メソッド グループ '{0}' を非デリゲート型 '{1}' に変換中です。このメソッドを呼び出すつもりでしたか? Converting method group to non-delegate type - Converting method group to non-delegate type + メソッド グループを非デリゲート型に変換しています Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + パラメーター '{0}' は null チェックされていますが、既定では null です。 Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + パラメーターは null チェックされていますが、既定では null です。 Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + Null 許容型 '{0}' は null チェックされており、null の場合はスローされます。 Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + Null 許容型は null チェックされており、null の場合はスローされます。 @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - パラメーター リスト内の {1} の後にパラメーター {0} が発生しますが、補間された文字列ハンドラー変換の引数として使用されます。呼び出し元が呼び出しサイトで名前付き引数を使用してパラメーターを並べ替える必要があります。関係するすべての引数の後に、補間された文字列ハンドラーのパラメーターを指定することを検討してください。 + パラメーター リスト内の '{1}' の後にパラメーター '{0}' が発生しますが、補間された文字列ハンドラーの変換の引数として使用されます。呼び出し元が呼び出しサイトで名前付き引数を使用してパラメーターを並べ替える必要があります。関係するすべての引数の後に、補間された文字列ハンドラーのパラメーターを指定することを検討してください。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 9e04e2983966b..af4df686fb692 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + '{0}'은(는) nullable이 될 수 없습니다. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + 'UnmanagedCallersOnly'로 특성이 지정된 메서드의 시그니처에는 'ref', 'in' 또는 'out'을 사용할 수 없습니다. @@ -357,6 +357,11 @@ 'not' 또는 'or' 패턴 안에 변수를 선언할 수 없습니다. + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. 무시 패턴은 switch 문의 case 레이블로 사용할 수 없습니다. 무시 패턴에 대해 'case var _:'을 사용하거나 이름이 '_'인 상수에 대해 'case @_:'을 사용하세요. @@ -407,6 +412,11 @@ 'else'로 문을 시작할 수 없습니다. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. 애플리케이션 진입점에는 'UnmanagedCallersOnly' 특성을 지정할 수 없습니다. @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + 식 트리에는 System.Index 또는 System.Range 패턴의 인덱서 액세스를 포함할 수 없습니다. @@ -597,6 +607,11 @@ 이 매개 변수에 해당 하는 위치 멤버 '{0}'이(가) 숨겨집니다. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context 이 컨텍스트에서는 비표시 오류(Suppression) 연산자를 사용할 수 없습니다. @@ -632,11 +647,6 @@ 동적으로 디스패치된 식에서 'in' 한정자가 있는 인수를 사용할 수 없습니다. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. 봉인된 'Object.ToString'이 있는 레코드에서 상속은 C# {0}에서 지원되지 않습니다. 언어 버전 '{1}'이상을 사용하세요. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + 인덱싱되는 인스턴스를 참조하는 보간된 문자열 처리기 변환은 인덱서 멤버 이니셜라이저에서 사용할 수 없습니다. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + 'var' 상황별 키워드는 명시적 람다 반환 형식으로 사용할 수 없습니다. A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + 특성이 있는 람다 식은 식 트리로 변환할 수 없습니다. + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - Slice patterns may only be used once and directly inside a list pattern. + 조각 패턴은 목록 패턴 내에서 바로 한 번만 사용할 수 있습니다. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + 매개 변수 '{0}'은(는) 구현 메서드에서 느낌표 Null 검사만 포함할 수 있습니다. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + 축자가 아닌 보간된 문자열 내의 줄 바꿈은 C# {0}에서 지원되지 않습니다. {1} 이상의 언어 버전을 사용하세요. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + 매개 변수 '{0}'은(는) Null을 허용하지 않는 값 형식이므로 Null을 검사할 수 없습니다. @@ -927,6 +947,16 @@ 매개 변수가 없는 구조체 생성자는 '공개'여야 합니다. + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. '{0}'은(는) 인스턴스 메서드가 아니므로 수신기는 보간된 문자열 처리기 인수가 될 수 없습니다. @@ -937,9 +967,9 @@ 포함된 레코드가 봉인되지 않았으므로 '{0}'은(는) 재정의를 허용해야 합니다. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ 속성 하위 패턴은 일치시킬 속성 또는 필드에 대한 참조가 필요합니다(예: '{{ Name: {0} }}') + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. '{0}' 형식에는 기본 인터페이스 멤버의 재추상화가 있으므로 해당 형식을 포함할 수 없습니다. 'Interop 형식 포함' 속성을 false로 설정해 보세요. @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + 매개 변수 목록을 사용하여 '레코드 구조체'에 선언된 생성자에는 기본 생성자 또는 명시적으로 선언된 생성자를 호출하는 'this' 이니셜라이저가 있어야 합니다. @@ -1222,9 +1272,14 @@ stdin 인수 '-'를 지정했지만 표준 입력 스트림에서 입력이 리디렉션되지 않았습니다. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + 필드 이니셜라이저가 있는 '구조체'에는 명시적으로 선언된 생성자가 포함되어야 합니다. @@ -1247,6 +1302,21 @@ 식을 제어하는 switch 주위에 괄호가 필요합니다. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. 최상위 문은 네임스페이스 및 형식 선언 앞에 와야 합니다. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + 목록 패턴은 '{0}' 형식 값에 사용할 수 없습니다. Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + 조각 패턴은 '{0}' 형식 값에 사용할 수 없습니다. + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ 람다 반환 유형 - - length pattern - length pattern - - line span directive 라인 범위 지시문 @@ -1389,12 +1459,12 @@ list pattern - list pattern + 목록 패턴 newlines in interpolations - newlines in interpolations + 보간에서 줄 바꿈 @@ -1407,6 +1477,11 @@ 레코드의 위치 필드 + + raw string literals + raw string literals + + record structs 레코드 구조체 @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + 매개 변수 Null 확인 @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + 작업이 런타임에 '{0}'을(를) 오버플로할 수 있습니다('선택되지 않은' 구문을 사용하여 재정의). The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + 작업이 런타임에 오버플로될 수 있습니다('선택되지 않은' 구문을 사용하여 재정의). @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + 형식 이름 '{0}'에는 소문자 ASCII 문자만 포함됩니다. 이러한 이름은 언어에 대해 예약될 수 있습니다. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + 형식 이름에는 소문자 ASCII 문자만 포함됩니다. 이러한 이름은 언어에 대해 예약될 수 있습니다. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + 메서드 그룹 '{0}'을(를) 비 위임 유형 '{1}'(으)로 변환하는 중입니다. 메서드를 호출하려고 했습니까? Converting method group to non-delegate type - Converting method group to non-delegate type + 메소드 그룹을 비 위임 유형으로 변환 Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + 매개 변수 '{0}'은(는) Null로 확인되었지만 기본적으로 Null입니다. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + 매개 변수가 Null로 확인되었지만 기본적으로 Null입니다. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + nullable 형식 '{0}'은(는) Null로 확인되었으며 Null이면 throw됩니다. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + nullable 형식은 Null로 확인되며 Null이면 throw됩니다. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - 매개 변수 {0}은 매개 변수 목록에서 {1} 다음에 나타나지만 보간된 문자열 처리기 변환을 위한 인수로 사용됩니다. 이렇게 하려면 호출자가 호출 사이트에서 명명된 인수를 사용하여 매개 변수를 재정렬해야 합니다. 관련된 모든 인수 뒤에 보간된 문자열 처리기 매개 변수를 넣는 것을 고려하세요. + ‘{0}’ 매개 변수는 매개 변수 목록에서 ‘{1}’ 다음에 나타나지만 보간된 문자열 처리기 변환을 위한 인수로 사용됩니다. 이렇게 하려면 호출자가 호출 사이트에서 명명된 인수를 사용하여 매개 변수를 재정렬해야 합니다. 관련된 모든 인수 뒤에 보간된 문자열 처리기 매개 변수를 넣는 것을 고려하세요. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index e63aeadcf0f96..ddccf8e5efe7a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + 'Nie można ustawić elementu „{0}” jako dopuszczającego wartość null. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + Nie można użyć elementów „ref”, „in” ani „out” w sygnaturze metody z atrybutem „UnmanagedCallersOnly”. @@ -357,6 +357,11 @@ Nie można deklarować zmiennej we wzorcu „not” ani „or”. + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. Wzorzec odrzucania nie jest dozwolony jako etykieta instrukcji case w instrukcji switch. Użyj instrukcji „case var _:” w przypadku wzorca odrzucania lub użyj instrukcji „case @_:” w przypadku stałej o nazwie „_”. @@ -407,6 +412,11 @@ Instrukcja nie może rozpoczynać się od elementu „else”. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Punkty wejścia aplikacji nie mogą mieć atrybutu „UnmanagedCallersOnly”. @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + Drzewo wyrażenia nie może zawierać dostępu do indeksatora z wzorcem System.Index lub System.Range @@ -597,6 +607,11 @@ Odnaleziony członek pozycyjny „{0}” odpowiadający temu parametrowi jest ukryty. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context Operator pominięcia jest niedozwolony w tym kontekście @@ -632,11 +647,6 @@ Nie można używać argumentów z modyfikatorem „in” w wyrażeniach przydzielanych dynamicznie. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. Dziedziczenie z rekordu z zapieczętowanym obiektem "Object.ToString" nie jest obsługiwane w języku C# {0}. Użyj wersji języka "{1}" lub nowszej. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + W inicjatorach składowych indeksatora nie można używać konwersji procedury obsługi ciągów interpolowanych odwołujących się do indeksowanego wystąpienia. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + Kontekstowego słowa kluczowego „var” nie można użyć jako jawnego zwracanego typu lambda A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + Nie można przekonwertować wyrażenia lambda z atrybutami na drzewo wyrażeń + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - 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. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + Parametr „{0}” może być sprawdzony tylko przy użyciu wartości null dla wykrzyknika w metodach implementacji. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + Nowe wiersze wewnątrz ciągu interpolowanego nie będącego ciągiem dosłownym nie są obsługiwane w {0} języka C#. Użyj wersji językowej {1} lub nowszej. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + Parametr „{0}” jest typem wartości, który nie dopuszcza wartości null i nie może być sprawdzony przy użyciu wartości null. @@ -927,6 +947,16 @@ Konstruktor struktury bez parametrów musi mieć wartość „public”. + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. "{0}" nie jest metodą wystąpienia, a odbiorca nie może być argumentem procedury obsługi ciągu interpolowanego. @@ -937,9 +967,9 @@ Element „{0}” musi zezwalać na przesłanianie, ponieważ zawierający go rekord nie jest zapieczętowany. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ Wzorzec podrzędny właściwości wymaga odwołania do właściwości lub pola, które należy dopasować, na przykład „{{ Name: {0} }}” + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. Nie można osadzić typu „{0}”, ponieważ zawiera ponowną abstrakcję składowej z interfejsu podstawowego. Rozważ ustawienie właściwości „Osadź typy międzyoperacyjne” na wartość false. @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + Konstruktor zadeklarowany w „strukturze rekordów” z listą parametrów musi mieć inicjator „this”, który wywołuje konstruktor podstawowy lub jawnie zadeklarowany konstruktor. @@ -1222,9 +1272,14 @@ określono argument stdin „-”, ale dane wejściowe nie zostały przekierowane ze standardowego strumienia wejściowego. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + Element „struct” z inicjatorami pól musi zawierać jawnie zadeklarowanego konstruktora. @@ -1247,6 +1302,21 @@ Wymagane są nawiasy wokół wyrażenia sterującego instrukcją switch. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. Instrukcje najwyższego poziomu muszą poprzedzać deklaracje przestrzeni nazw i typów. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + Wzorców list nie można używać na potrzeby wartości typu „{0}”. Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + Wzorców wycinków nie można używać na potrzeby wartości typu „{0}”. + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ zwracany typ lambda - - length pattern - length pattern - - line span directive dyrektywa zakresu wierszy @@ -1389,12 +1459,12 @@ list pattern - list pattern + wzorzec listy newlines in interpolations - newlines in interpolations + nowe wiersze w interpolacjach @@ -1407,6 +1477,11 @@ pola pozycyjne w rekordach + + raw string literals + raw string literals + + record structs struktury rekordów @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + sprawdzanie wartości null parametru @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + Operacja może się przepełnić w środowisku uruchomieniowym „{0}” (użyj składni „niezaznaczone”, aby zastąpić) The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + Operacja może się przepełnić w środowisku uruchomieniowym (użyj składni „niezaznaczone”, aby zastąpić) @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + Nazwa typu „{0}” zawiera tylko małe litery ascii. Takie nazwy mogą zostać zarezerwowane dla języka. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + Nazwa typu zawiera tylko małe litery ascii. Takie nazwy mogą zostać zarezerwowane dla języka. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + Konwertowanie grupy metod „{0}” na typ inny niż delegowany „{1}”. Czy zamierzasz wywołać metodę? Converting method group to non-delegate type - Converting method group to non-delegate type + Konwertowanie grupy metod na typ inny niż delegowany Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + Parametr „{0}” jest sprawdzony przy użyciu wartości null, ale domyślnie ma wartość null. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + Parametr jest sprawdzony przy użyciu wartości null, ale domyślnie ma wartość null. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + Typ dopuszczający wartość null „{0}” jest sprawdzany przy użyciu wartości null i będzie widoczny w przypadku wartości null. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + Typ dopuszczający wartość null jest sprawdzony przy użyciu wartości null i będzie widoczny w przypadku wartości null. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - Parametr {0} występuje po {1} na liście parametrów, ale jest on używany jako argument dla konwersji procedury obsługi ciągów interpolowanych. Będzie to wymagać od wywołującego zmiany kolejności parametrów za pomocą nazwanych argumentów w lokacji wywołania. Rozważ umieszczenie parametru procedury obsługi ciągu interpolowanego po wszystkich zastosowanych argumentach. + Parametr „{0}” występuje po elemencie „{1}” na liście parametrów, ale jest on używany jako argument dla konwersji procedury obsługi ciągów interpolowanych. Będzie to wymagać od wywołującego zmiany kolejności parametrów za pomocą nazwanych argumentów w lokacji wywołania. Rozważ umieszczenie parametru procedury obsługi ciągu interpolowanego po wszystkich zastosowanych argumentach. @@ -2789,12 +2864,12 @@ Converting null literal or possible null value to non-nullable type. - Konwertowanie literału o wartości null lub możliwej wartości null na nienullowalny typ. + Konwertowanie literału null lub możliwej wartości null na nienullowalny typ. Converting null literal or possible null value to non-nullable type. - Konwertowanie literału o wartości null lub możliwej wartości null na nienullowalny typ. + Konwertowanie literału null lub możliwej wartości null na nienullowalny typ. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 27d01ea964fd3..c5b9a039cd6fc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + '{0}' não pode ser tornado anulável. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + Não é possível usar 'ref', 'in' ou 'out' na assinatura de um método atribuído com 'UnmanagedCallersOnly'. @@ -357,6 +357,11 @@ Uma variável não pode ser declarada em um padrão 'not' ou 'or'. + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. O padrão de descarte não é permitido como um rótulo de caso em uma instrução switch. Use 'case var _:' para um padrão de descarte ou 'case @_:' para uma constante chamada '_'. @@ -407,6 +412,11 @@ 'else' não pode iniciar uma instrução. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Os pontos de entrada do aplicativo não podem ser atribuídos com 'UnmanagedCallersOnly'. @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + Uma árvore de expressão não pode conter um padrão System.Index ou acesso do indexador System.Range @@ -597,6 +607,11 @@ O membro posicional “{0}” encontrado correspondente a este parâmetro está oculto. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context O operador de supressão não é permitido neste contexto @@ -632,11 +647,6 @@ Os argumentos com o modificador 'in' não podem ser usados em expressões vinculadas dinamicamente. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. Herdar de um registro com um 'Object.ToString' selado não é compatível com C# {0}. Use a versão do idioma '{1}' ou superior. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + Conversões do manipulador de cadeia de caracteres interpoladas que fazem referência à instância que está sendo indexada não podem ser usadas em inicializadores de membros indexadores. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + A palavra-chave contextual 'var' não pode ser usada como um tipo de retorno de lambda explícito A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + Uma expressão lambda com atributos não pode ser convertida em uma árvore de expressão + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - 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. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + O parâmetro '{0}' só pode ter verificação nula de ponto de exclamação nos métodos de implementação. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + Novas linhas dentro de uma cadeia de caracteres interpolada não textual não são suportadas no C# {0}. Use a versão {1} da linguagem ou superior. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + O parâmetro '{0}' é um tipo de valor não anulável e não pode ser verificado como nulo. @@ -927,6 +947,16 @@ O Construtor struct sem parâmetros deve ser 'Public'. + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. '{0}' não é um método de instância, o receptor não pode ser um argumento de manipulador de cadeia de caracteres interpolada. @@ -937,9 +967,9 @@ '{0}' precisa permitir a substituição porque o registro contentor não está selado. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ Um subpadrão de propriedade requer que uma referência à propriedade ou ao campo seja correspondida, por exemplo, '{{ Name: {0} }}' + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. O tipo '{0}' não pode ser inserido porque tem uma nova abstração de um membro da interface base. Considere a configuração da propriedade 'Embed Interop Types' como false. @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + Um construtor declarado em uma 'estrutura de registro' com lista de parâmetros deve ter um inicializador 'este' que chama o construtor primário ou um construtor declarado explicitamente. @@ -1222,9 +1272,14 @@ O argumento stdin '-' foi especificado, mas a entrada não foi redirecionada do fluxo de entrada padrão. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + Uma 'estrutura' com inicializadores de campo deve incluir um construtor declarado explicitamente. @@ -1247,6 +1302,21 @@ É necessário colocar a expressão que rege a switch entre parênteses. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. As instruções de nível superior precisam preceder as declarações de namespace e de tipo. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + Os padrões de lista não podem ser usados para um valor do tipo '{0}'. Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + Os padrões de fatia não podem ser usados para um valor do tipo '{0}'. + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ tipo de retorno de lambda - - length pattern - length pattern - - line span directive diretiva de extensão de linha @@ -1389,12 +1459,12 @@ list pattern - list pattern + padrão de lista newlines in interpolations - newlines in interpolations + novas linhas em interpolações @@ -1407,6 +1477,11 @@ campos posicionais nos registros + + raw string literals + raw string literals + + record structs registrar structs @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + parâmetro de verificação nula @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + A operação pode estourar '{0}' em tempo de execução (use a sintaxe 'não verificada' para substituir) The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + A operação pode estourar em tempo de execução (use a sintaxe 'não verificada' para substituir) @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + O nome do tipo '{0}' contém apenas caracteres ascii em caixa baixa. Esses nomes podem ficar reservados para o idioma. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + O nome do tipo contém apenas caracteres ascii em caixa baixa. Esses nomes podem ficar reservados para o idioma. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + Convertendo grupo de métodos '{0}' em tipo não delegado '{1}'. Você pretendia invocar o método? Converting method group to non-delegate type - Converting method group to non-delegate type + Convertendo grupo de método em tipo não delegado Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + O parâmetro '{0}' é verificado como nulo, mas é nulo por padrão. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + O parâmetro é verificado como nulo, mas é nulo por padrão. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + O tipo anulável '{0}' é verificado como nulo e será lançado se for nulo. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + O tipo anulável é verificado como nulo e será lançado se for nulo. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - O parâmetro {0} ocorre após {1} na lista de parâmetros, mas é usado como um argumento para as conversões do manipulador de cadeia de caracteres interpolada. Isso exigirá que o chamador reordene os parâmetros com argumentos nomeados no local de chamada. Considere colocar o parâmetro do manipulador de cadeia de caracteres interpolada após todos os argumentos envolvidos. + O parâmetro {0} ocorre após {1} na lista de parâmetros, mas é usado como um argumento para as conversões do manipulador de cadeia de caracteres interpolada. Isso exigirá que o chamador reordene os parâmetros com argumentos nomeados no local da chamada. Considere colocar o parâmetro do manipulador de cadeia de caracteres interpolada após todos os argumentos envolvidos. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 4d1605ea58f06..28db678c6a3bd 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + "{0}" не может быть стать параметром, допускающим NULL. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + Нельзя использовать "ref", "in" или "out" в сигнатуре метода с атрибутом "UnmanagedCallersOnly". @@ -357,6 +357,11 @@ Переменная не может быть объявлена в шаблоне "not" или "or". + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. Шаблон отмены запрещено использовать как метку case в операторе switch. Используйте "case var _:" в качестве шаблона отмены или "case @_:" в качестве константы "_". @@ -407,6 +412,11 @@ "else" не может запускать оператор. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Точки входа приложения не могут иметь атрибут "UnmanagedCallersOnly". @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + Дерево выражения не может содержать доступ к индексатору System.Index или System.Range шаблона. @@ -597,6 +607,11 @@ Обнаруженный позиционный элемент "{0}", соответствующий этому параметру, скрыт. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context Оператор подавления недопустим в данном контексте. @@ -632,11 +647,6 @@ Аргументы с модификатором "in" невозможно использовать в динамически диспетчеризируемых выражениях. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. Наследование от записи с запечатанным Object. ToString не поддерживается в C# {0}. Используйте версию языка "{1}" или более позднюю. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + Преобразования обработчика интерполированной строки, ссылающиеся на индексируемый экземпляр, нельзя использовать в инициализаторах элементов индексатора. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + Контекстное ключевое слово "var" нельзя использовать в качестве явного типа возвращаемого значения лямбда-выражения A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + Невозможно преобразовать лямбда-выражение с атрибутами в дерево выражения + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - Slice patterns may only be used once and directly inside a list pattern. + Шаблоны среза можно использовать только один раз и непосредственно внутри шаблона списка. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + Для параметра "{0}" может использоваться только проверка значений NULL с восклицательным знаком в методах реализации. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + Новые строки внутри небуквальной интерполированной строки не поддерживаются в C# {0}. Используйте версию языка {1} или более позднюю. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + Параметр "{0}" является типом значения, не допускающим значения NULL, и для него невозможно выполнить проверку значения NULL. @@ -927,6 +947,16 @@ Конструктор структуры без параметров должен быть публичным. + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. Поскольку "{0}" не является методом экземпляра, получатель не может быть аргументом обработчика интерполированных строк. @@ -937,9 +967,9 @@ "{0}" должен допускать переопределение, поскольку содержащая его запись не является запечатанной. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ Для вложенного шаблона свойств требуется ссылка на свойство или поле для сопоставления, например, "{{ Name: {0} }}". + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. Невозможно внедрить тип "{0}", так как он переопределяет абстракцию элемента базового интерфейса. Попробуйте задать для свойства "Внедрить типы взаимодействия" значение false (ложь). @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + Конструктор, объявленный в "record struct" со списком параметров, должен содержать инициализатор "this", который вызывает первичный конструктор или явно объявленный конструктор. @@ -1222,9 +1272,14 @@ Указан аргумент stdin "-", но входные данные не были перенаправлены из стандартного входного потока. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + Параметр struct с инициализаторами полей должен включать явно объявленный конструктор. @@ -1247,6 +1302,21 @@ Вокруг главного выражения switch требуются скобки. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. Инструкции верхнего уровня должны предшествовать объявлениям пространств имен и типов. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + Шаблоны списка не могут использоваться для значений типа "{0}". Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + Шаблоны среза не могут использоваться для значений типа "{0}". + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ тип возвращаемого значения лямбда - - length pattern - length pattern - - line span directive директива line span @@ -1389,12 +1459,12 @@ list pattern - list pattern + шаблон списка newlines in interpolations - newlines in interpolations + новые линии в интерполяции @@ -1407,6 +1477,11 @@ позиционные поля в записях + + raw string literals + raw string literals + + record structs структуры записей @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + проверка значений NULL для параметра @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + Операция может привести к переполнению "{0}" в среде выполнения (для переопределения используйте синтаксис "unchecked") The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + Операция может привести к переполнению в среде выполнения (для переопределения используйте синтаксис "unchecked") @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + Имя типа "{0}" содержит только строчные символы ASCII. Такие имена могут резервироваться для языка. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + Имя типа содержит только строчные символы ASCII. Такие имена могут резервироваться для языка. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + Преобразование группы методов "{0}" в незаменяемый тип "{1}". Вы намеревались вызвать этот метод? Converting method group to non-delegate type - Converting method group to non-delegate type + Преобразование группы методов в незаменямый тип Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + Для параметра "{0}" выполнена проверка значения NULL, но он по умолчанию имеет значение NULL. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + Для параметра выполнена проверка значения NULL, но он по умолчанию имеет значение NULL. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + Для типа "{0}", допускающего значение NULL, выполнена проверка значения NULL. Он будет выдаваться, если ему присвоено значение NULL. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + Для типа, допускающего значение NULL, выполнена проверка значения NULL. Он будет выдаваться, если ему присвоено значение NULL. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - Параметр {0} указан после {1} в списке параметров, но используется в качестве аргумента для преобразований обработчика интерполированных строк. В этом случае вызывающий должен изменить порядок параметров с именованными аргументами на сайте вызова. Рекомендуем разместить параметр обработчика интерполированных строк после всех используемых аргументов. + Параметр {0} указан после {1} в списке параметров, но используется в качестве аргумента для преобразований обработчика интерполированных строк. В этом случае вызывающий должен изменить порядок параметров с именованными аргументами на сайте вызова. Рекомендуем разместить параметр обработчика интерполированных строк после всех используемых аргументов. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index e57aeda4a8658..e7d05e3df7689 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + '{0}' öğesine null değer alma özelliği verilemiyor. @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + 'UnmanagedCallersOnly' özniteliğine sahip bir metodun imzasında 'ref', 'in' veya 'out' kullanılamaz. @@ -357,6 +357,11 @@ 'Değil' ya da 'veya' deseninde değişken bildirilemez. + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. Bir switch deyiminde case etiketi olarak atma desenine izin verilmez. Atma deseni için 'case var _:' veya '_' adlı bir sabit için 'case @_:' seçeneğini kullanın. @@ -407,6 +412,11 @@ 'else' bir deyim başlatamaz. + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Uygulama giriş noktaları 'UnmanagedCallersOnly' ile ilişkilendirilemez. @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + İfade ağacı, desen System.Index veya System.Range dizin oluşturucu erişimi içeremez @@ -597,6 +607,11 @@ Bu parametreye karşılık gelen konumsal üye '{0}' gizli. + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context Gizleme işlecine bu bağlamda izin verilmez @@ -632,11 +647,6 @@ 'in' değiştiricisine sahip bağımsız değişkenler dinamik olarak dağıtılan ifadelerde kullanılamaz. - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. Mühürlü bir 'Object.ToString' içeren bir kayıttan devralma işlemi C# {0} sürümünde desteklenmiyor. Lütfen '{1}' veya üstü bir dil sürümünü kullanın. @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + Dizine alınan örneğe başvurulan düz metin arasına kod ekli dize işleyici dönüştürmeleri, dizin oluşturucu üye başlatıcılarında kullanılamaz. @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + Bağlamsal 'var' anahtar sözcüğü, açık lambda dönüş türü olarak kullanılamaz A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + Öznitelikleri olan bir lambda ifadesi bir ifade ağacına dönüştürülemez + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - 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. @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + “{0}” parametresi, uygulama yöntemlerinde yalnızca ünlem işareti null denetimine sahip olabilir. @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + Tam olmayan düz metin arasına kod eklenmiş dize içindeki yeni satırlar, C# {0} içinde desteklenmiyor. Lütfen {1} dil sürümünü veya daha üstünü kullanın. @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + “{0}” parametresi, null atanamaz bir değer türüdür ve null denetimi yapılamaz. @@ -927,6 +947,16 @@ Parametresiz yapı oluşturucusu 'public' olmalıdır. + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. '{0}' bir örnek metodu değil; alıcı, düz metin arasına kod eklenmiş dize işleyici bağımsız değişkeni olamaz. @@ -937,9 +967,9 @@ '{0}', kapsayan kayıt mühürlü olmadığından geçersiz kılmaya izin vermelidir. - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ Bir özellik alt deseni, özellik veya alan başvurusunun eşleşmesini gerektiriyor, ör. '{{ Name: {0} }}' + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. '{0}' türünün temel arabirimden yeniden soyutlanmış bir üyesi olduğundan bu tür eklenemiyor. 'Embed Interop Types' özelliğini false olarak ayarlamayı deneyin. @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + Parametre listesiyle bir “kayıt yapısı”nda bildirilen bir oluşturucu, birincil oluşturucuyu veya açıkça bildirilen bir oluşturucuyu çağıran bir “this” başlatıcısına sahip olmalıdır. @@ -1222,9 +1272,14 @@ '-' stdin bağımsız değişkeni belirtildi ancak giriş, standart giriş akışından yeniden yönlendirilmedi. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + Alan başlatıcılarına sahip bir 'struct' açıkça bildirilen bir oluşturucu içermelidir. @@ -1247,6 +1302,21 @@ Switch yönetim ifadesinin parantez içine alınması gerekir. + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. Üst düzey deyimler ad alanı ve tür bildirimlerinden önce gelmelidir. @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + Liste desenleri, '{0}' türünde bir değer için kullanılamaz. Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + Dilim desenleri, '{0}' türünde bir değer için kullanılamaz. + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ lambda dönüş türü - - length pattern - length pattern - - line span directive satır aralığı yönergesi @@ -1389,12 +1459,12 @@ list pattern - list pattern + liste deseni newlines in interpolations - newlines in interpolations + ilişkilendirmedeki yeni satırlar @@ -1407,6 +1477,11 @@ kayıtlardaki konumsal alanlar + + raw string literals + raw string literals + + record structs kayıt yapıları @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + parametre null denetimi @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + İşlem, çalışma zamanında “{0}” öğesini taşabilir (geçersiz kılmak için “denetlenmemiş” söz dizimini kullanın) The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + İşlem, çalışma zamanında taşabilir (geçersiz kılmak için “denetlenmemiş” sözdizimini kullanın) @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + “{0}” tür adı yalnızca küçük harfli ascii karakterleri içerir. Bu tür adlar dil için ayrılmış hale gelebilir. The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + Tür adı yalnızca küçük harfli ascii karakterleri içerir. Bu tür adlar dil için ayrılmış hale gelebilir. Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + “{0}” yöntem grubunu temsilci olmayan tip “{1}”e dönüştürme. Yöntemi çağırmayı düşündünüz mü? Converting method group to non-delegate type - Converting method group to non-delegate type + Yöntem grubunu temsilci olmayan türe dönüştürme Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + “{0}” parametresi null denetimlidir ancak varsayılan olarak null’dürr. Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + Parametre null denetimlidir ancak varsayılan olarak null’dür. Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + “{0}” boş değer atanabilir tipi null denetimlidir ve null ise atılır. Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + Boş değer atanabilir tip null denetimlidir ve null ise atılır. @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - Parametre listesinde parametre {0}, ardından parametre {1} gerçekleşir, ancak düz metin arasına kod eklenmiş dize işleyicisi dönüştürmeleri için bağımsız değişken olarak kullanılır. Bu, çağıranın, çağıran sitede adlandırılmış bağımsız değişkenlerle parametreleri yeniden düzenlemesini gerektirir. Tüm bağımsız değişkenlerin ardından düz metin arasına kod eklenmiş dize işleyicisi parametresini yerleştirmeyi göz önünde bulundurmanız gerekir. + Parametre listesinde parametre {0}, ardından parametre {1} gerçekleşir, ancak düz metin arasına kod eklenmiş dize işleyicisi dönüştürmeleri için bağımsız değişken olarak kullanılır. Bu, çağıranın, çağıran sitede adlandırılmış bağımsız değişkenlerle parametreleri yeniden düzenlemesini gerektirir. Tüm bağımsız değişkenlerin ardından düz metin arasına kod eklenmiş dize işleyicisi parametresini yerleştirmeyi göz önünde bulundurmanız gerekir. @@ -7166,7 +7241,7 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm Declaration is not valid; use '{0} operator <dest-type> (...' instead - Bildirim geçerli değil; bunun yerine '{0} işleç < hedef-tür> (...' kullanın + Bildirim geçerli değil; bunun yerine '{0} işleç <hedef-tür> (...' kullanın @@ -7761,7 +7836,7 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. - Zaman uyumsuz {0}, '{1}' temsilci türüne dönüştürülemez. Zaman uyumsuz {0} void, Task veya Task< T> döndürebilir ve bunların hiçbiri '{1}' türüne dönüştürülemez. + Zaman uyumsuz {0}, '{1}' temsilci türüne dönüştürülemez. Zaman uyumsuz {0} void, Task veya Task<T> döndürebilir ve bunların hiçbiri '{1}' türüne dönüştürülemez. @@ -8964,7 +9039,7 @@ Derleyiciye yöntemleri ayrıştırma yolu verin. Örneğin, bunlara farklı adl The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task<{0}>'. - await' işleci yalnızca bir async metot içerisinde kullanılabilir. Bu metodu 'async' değiştiricisi ile işaretlemeyi ve dönüş tipini 'Task<{0}>' olarak değiştirmeyi düşünün. + 'await' işleci yalnızca bir async metot içerisinde kullanılabilir. Bu metodu 'async' değiştiricisi ile işaretlemeyi ve dönüş tipini 'Task<{0}>' olarak değiştirmeyi düşünün. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 9ec1f386e046e..9b7921d083205 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + “{0}”不可以为 Null。 @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + 无法在具有 “UnmanagedCallersOnly” 特性的方法的签名中使用 “ref”、“in” 或 “out”。 @@ -357,6 +357,11 @@ 在“not”或“or”模式中不能声明变量。 + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. 在 switch 语句中,不允许将放弃模式作为 case 标签。请使用“case var _:”以表示放弃模式、使用“case @_:”以定义名为“_”的变量。 @@ -407,6 +412,11 @@ "else" 不能用在语句的开头。 + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. 无法使用 "UnmanagedCallersOnly" 对应用程序入口点进行特性化。 @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + 表达式树不能包含模式 System.Index 或 System.Range 索引器访问 @@ -597,6 +607,11 @@ 已隐藏找到的此参数相应位置成员“{0}”。 + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context 此上下文中不允许使用抑制运算符 @@ -632,11 +647,6 @@ 带有 "in" 修饰符的参数不能用于动态调度的表达式。 - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. C# {0} 中不支持从包含密封 'Object.ToString' 的记录继承。请使用语言版本 '{1}’ 或更高版本。 @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + 引用要编制索引的实例的内插字符串处理程序转换不能用于索引器成员初始化表达式中。 @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + 上下文关键字 “var” 不能用作显式 lambda 返回类型 A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + 无法将具有属性的 lambda 表达式转换为表达式树 + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - Slice patterns may only be used once and directly inside a list pattern. + 切片模式只能使用一次,并且直接在列表模式内使用。 @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + 参数 "{0}" 只能在实现方法中包含感叹号 null 检查。 @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + C# {0}不支持非逐字内插字符串内的换行符。请使用语言版本 {1} 或更高版本。 @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + 参数 "{0}" 是不可为 null 的值类型,不能进行 null 检查。 @@ -927,6 +947,16 @@ 参数结构构造函数必须是“public”。 + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. “{0}”不是实例方法,接收器不能是内插字符串处理程序参数。 @@ -937,9 +967,9 @@ “{0}”必须允许替代,因为包含的记录未密封。 - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ 属性子模式需要引用要匹配的属性或字段,例如,"{{ Name: {0} }}" + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. 无法嵌入类型“{0}”,因为它有基本接口成员的重新抽象。请考虑将“嵌入互操作类型”属性设置为 false。 @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + 在带有参数列表的 "record struct" 中声明的构造函数必须具有调用主构造函数或显式声明的构造函数的 "this" 初始值设定项。 @@ -1222,9 +1272,14 @@ 已指定 stdin 参数 "-",但尚未从标准输入流重定向输入。 + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + 具有字段初始值设定项的“结构”必须包含显式声明的构造函数。 @@ -1247,6 +1302,21 @@ switch governing 表达式的周围需要括号。 + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. 顶级语句必须位于命名空间和类型声明之前。 @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + 列表模式不能用于类型为“{0}”的值。 Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + 切片模式不能用于类型为“{0}”的值。 + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ lambda 返回类型 - - length pattern - length pattern - - line span directive 行跨度指令 @@ -1389,12 +1459,12 @@ list pattern - list pattern + 列表模式 newlines in interpolations - newlines in interpolations + 内插中的换行符 @@ -1407,6 +1477,11 @@ 记录中的位置字段 + + raw string literals + raw string literals + + record structs 记录结构 @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + 参数 null 检查 @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + 操作可能在运行时溢出“{0}”(请使用“unchecked”语法替代) The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + 操作可能在运行时溢出(请使用“unchecked”语法替代) @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + 类型名称 "{0}" 仅包含小写 ascii 字符。此类名称可能会成为该语言的保留值。 The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + 该类型名称仅包含小写 ascii 字符。此类名称可能会成为该语言的保留值。 Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + 将方法组“{0}”转换为非委托类型“{1}”。是否希望调用此方法? Converting method group to non-delegate type - Converting method group to non-delegate type + 将方法组转换为非委托类型 Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + 对参数 "{0}" 进行了 null 检查,但默认情况下该参数为 null。 Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + 对参数进行了 null 检查,但默认情况下该参数为 null。 Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + 对可以为 null 的类型“{0}”进行了 null 检查,如果为 null,将抛出异常。 Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + 对可以为 null 的类型进行了 null 检查,如果为 null,将抛出异常。 @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - 参数 {0} 在参数列表中的 {1} 后发生,但被用作内插字符串处理程序转换的参数。这将要求调用方在调用站点使用命名参数重新排列参数。请考虑将内插字符串处理程序参数放在涉及的所有参数的后面。 + 参数“{0}”出现在参数列表中的“{1}”之后,但用作内插字符串处理程序转换的参数。这将要求调用方在调用站点使用已命名参数重新排列参数。请考虑将内插字符串处理程序参数放在涉及的所有参数的后面。 @@ -2319,7 +2394,7 @@ <switch expression> - <switch expression> + <开关表达式> diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 1dfbb00bff7c8..170d3788b4231 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -224,7 +224,7 @@ '{0}' cannot be made nullable. - '{0}' cannot be made nullable. + '{0}' 不可為 Null。 @@ -264,7 +264,7 @@ Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + 無法在具有 'UnmanagedCallersOnly' 的方法簽章中使用 'ref'、'in' 或 'out'。 @@ -357,6 +357,11 @@ 不得在 'not' 或 'or' 模式中宣告變數。 + + Discard parameter cannot be null-checked. + Discard parameter cannot be null-checked. + + The discard pattern is not permitted as a case label in a switch statement. Use 'case var _:' for a discard pattern, or 'case @_:' for a constant named '_'. 捨棄模式不可為 switch 陳述式中的 case 標籤。針對捨棄模式,請使用 'case var _:',針對名為 '_' 的常數,則請使用 'case @_:'。 @@ -407,6 +412,11 @@ 'else' 無法開始陳述式。 + + Cannot update because an inferred delegate type has changed. + Cannot update because an inferred delegate type has changed. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. 無法使用 'UnmanagedCallersOnly' 將應用程式進入點屬性化。 @@ -469,7 +479,7 @@ An expression tree may not contain a pattern System.Index or System.Range indexer access - An expression tree may not contain a pattern System.Index or System.Range indexer access + 運算式樹狀架構不可包含 System.Index 或 System.Range 索引子存取模式 @@ -597,6 +607,11 @@ 找到之與此參數對應的「{0}」位置成員已隱藏。 + + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + + The suppression operator is not allowed in this context 此內容不允許隱藏項目運算子 @@ -632,11 +647,6 @@ 具有 'in' 修飾元的引數不可用於動態分派的運算式。 - - Incorrect parameter null checking syntax. Should be '!!'. - Incorrect parameter null checking syntax. Should be '!!'. - - Inheriting from a record with a sealed 'Object.ToString' is not supported in C# {0}. Please use language version '{1}' or greater. C # {0} 不支援從具有密封的 'Object.ToString' 的記錄繼承。請使用 '{1}' 或更高的語言版本。 @@ -699,7 +709,7 @@ Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. - Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + 參考要編制索引的執行個體的差補字串處理常式轉換無法用於索引子成員初始化程式。 @@ -774,12 +784,22 @@ The contextual keyword 'var' cannot be used as an explicit lambda return type - The contextual keyword 'var' cannot be used as an explicit lambda return type + 內容關鍵字 'var' 不得做為明確的 Lambda 傳回型別 A lambda expression with attributes cannot be converted to an expression tree - A lambda expression with attributes cannot be converted to an expression tree + 具有屬性的 Lambda 運算式,不可轉換成運算式樹狀架構 + + + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + + + Line does not start with the same whitespace as the closing line of the raw string literal. + Line does not start with the same whitespace as the closing line of the raw string literal. @@ -799,7 +819,7 @@ Slice patterns may only be used once and directly inside a list pattern. - Slice patterns may only be used once and directly inside a list pattern. + 切片模式只能在清單模式中使用一次且直接使用。 @@ -859,7 +879,7 @@ Parameter '{0}' can only have exclamation-point null checking in implementation methods. - Parameter '{0}' can only have exclamation-point null checking in implementation methods. + 在實作方法中,參數 '{0}' 只能使用驚嘆號檢查是否為 Null。 @@ -869,7 +889,7 @@ Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. - Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. + C# {0} 不支援非逐字差補字串內的新行。請使用語言版本 {1} 或更高版本。 @@ -904,7 +924,7 @@ Parameter '{0}' is a non-nullable value type and cannot be null-checked. - Parameter '{0}' is a non-nullable value type and cannot be null-checked. + 參數 '{0}' 是不可為 Null 的實值型別,而且不能檢查是否為 Null。 @@ -927,6 +947,16 @@ 無參數結構建構函式必須是 'public'。 + + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + The interpolation must end with the same number of closing braces as the number of '$' characters that the raw string literal started with. + + + + Not enough quotes for raw string literal. + Not enough quotes for raw string literal. + + '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument. '{0}' 不是執行個體方法,接收器不可為差補字串處理常式引數。 @@ -937,9 +967,9 @@ '{0}' 必須允許覆寫,因為包含的記錄並未密封。 - - By-reference parameter '{0}' cannot be null-checked. - By-reference parameter '{0}' cannot be null-checked. + + 'out' parameter '{0}' cannot be null-checked. + 'out' parameter '{0}' cannot be null-checked. @@ -1062,6 +1092,26 @@ 屬性子模式需要對屬性或欄位的參考才能比對,例如 '{{ Name: {0} }}' + + Raw string literal delimiter must be on its own line. + Raw string literal delimiter must be on its own line. + + + + Multi-line raw string literals are only allowed in verbatim interpolated strings. + Multi-line raw string literals are only allowed in verbatim interpolated strings. + + + + Multi-line raw string literals must contain at least one line of content. + Multi-line raw string literals must contain at least one line of content. + + + + Raw string literals are not allowed in preprocessor directives. + Raw string literals are not allowed in preprocessor directives. + + Type '{0}' cannot be embedded because it has a re-abstraction of a member from base interface. Consider setting the 'Embed Interop Types' property to false. 因為類型 '{0}' 有重新抽象成員 (來自基底介面),所以無法內嵌。請考慮將 [內嵌 Interop 類型] 屬性設為 false。 @@ -1079,7 +1129,7 @@ A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. - A constructor declared in a 'record struct' with parameter list must have a 'this' initializer that calls the primary constructor or an explicitly declared constructor. + 使用參數清單在 'record struct' 中宣告的建構函式,必須有呼叫主要建構函式或已明確宣告建構函式的 'this' 初始設定式。 @@ -1222,9 +1272,14 @@ 已指定 stdin 引數 '-',但尚未從標準輸入資料流重新導向輸入。 + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. - A 'struct' with field initializers must include an explicitly declared constructor. + 具有欄位初始設定式的 'struct' 必須包含明確宣告的建構函式。 @@ -1247,6 +1302,21 @@ switch 主導的運算式前後必須有括弧。 + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + + + + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content. + + + + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + The raw string literal does not start with enough quote characters to allow this many consecutive quote characters as content. + + Top-level statements must precede namespace and type declarations. 最上層陳述式必須在命名空間和型別宣告之前。 @@ -1294,12 +1364,17 @@ List patterns may not be used for a value of type '{0}'. - List patterns may not be used for a value of type '{0}'. + 類型 '{0}' 的值不可使用清單模式。 Slice patterns may not be used for a value of type '{0}'. - Slice patterns may not be used for a value of type '{0}'. + 類型 '{0}' 的值不可使用切片模式。 + + + + Unterminated raw string literal. + Unterminated raw string literal. @@ -1377,11 +1452,6 @@ lambda 傳回型別 - - length pattern - length pattern - - line span directive line span 指示詞 @@ -1389,12 +1459,12 @@ list pattern - list pattern + 清單模式 newlines in interpolations - newlines in interpolations + 插補中的新行 @@ -1407,6 +1477,11 @@ 記錄中的位置欄位 + + raw string literals + raw string literals + + record structs 記錄結構 @@ -1444,7 +1519,7 @@ parameter null-checking - parameter null-checking + 檢查參數是否為 Null @@ -1529,12 +1604,12 @@ The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) - The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + 作業在執行階段可能會溢位 '{0}' (請使用 'unchecked' 語法覆寫) The operation may overflow at runtime (use 'unchecked' syntax to override) - The operation may overflow at runtime (use 'unchecked' syntax to override) + 作業在執行階段可能會溢位 (請使用 'unchecked' 語法覆寫) @@ -1559,42 +1634,42 @@ The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name '{0}' only contains lower-cased ascii characters. Such names may become reserved for the language. + 類型名稱 '{0}' 只包含小寫的 ASCII 字元。此類名稱可能保留供此語言使用。 The type name only contains lower-cased ascii characters. Such names may become reserved for the language. - The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + 類型名稱只包含小寫的 ASCII 字元。此類名稱可能保留供此語言使用。 Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? - Converting method group '{0}' to non-delegate type '{1}'. Did you intend to invoke the method? + 將方法群組 '{0}' 轉換成非委派類型 '{1}'。原本希望叫用該方法嗎? Converting method group to non-delegate type - Converting method group to non-delegate type + 將方法群組轉換為非委派類型 Parameter '{0}' is null-checked but is null by default. - Parameter '{0}' is null-checked but is null by default. + 已檢查參數 '{0}' 是否為 Null,但其本就預設為 Null。 Parameter is null-checked but is null by default. - Parameter is null-checked but is null by default. + 已檢查參數是否為 Null,但其本就預設為 Null。 Nullable type '{0}' is null-checked and will throw if null. - Nullable type '{0}' is null-checked and will throw if null. + 可為 Null 類型的 '{0}' 會檢查是否為 Null,若為 Null,則會擲回。 Nullable type is null-checked and will throw if null. - Nullable type is null-checked and will throw if null. + 可為 Null 的類型會檢查是否為 Null,若為 Null,則會擲回。 @@ -1609,7 +1684,7 @@ Parameter '{0}' occurs after '{1}' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. - 參數 {0} 發生在參數清單中 {1} 之後,但卻用為差補字串處理常式轉換的引數。這會要求呼叫者在呼叫網站使用具名引數重新排列參數。請考慮將差補字串處理常式參數置於所有相關的引數後面。 + 參數 {0} 發生在參數清單中 {1} 之後,但卻用為差補字串處理常式轉換的引數。這會要求呼叫者在呼叫網站使用具名引數重新排列參數。請考慮將差補字串處理常式參數置於所有相關的引數後面。 diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index 726df7260335e..206f936c3a5ff 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs @@ -11722,7 +11722,13 @@ public void LoadinganalyzerNetStandard13() at TestAnalyzer.get_SupportedDiagnostics() at Microsoft.CodeAnalysis.Diagnostics.AnalyzerManager.AnalyzerExecutionContext.<>c__DisplayClass20_0.b__0(Object _) at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock[TArg](DiagnosticAnalyzer analyzer, Action`1 analyze, TArg argument, Nullable`1 info) ------", outputWithoutPaths); +----- +Analyzer 'TestAnalyzer' threw the following exception: +'System.NotImplementedException: 28 + at TestAnalyzer.get_SupportedDiagnostics() + at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.CreateDisablingMessage(DiagnosticAnalyzer analyzer, String analyzerName) +----- +'.", outputWithoutPaths); Assert.Equal(0, result.ExitCode); } @@ -12497,6 +12503,11 @@ public void TestCategoryBasedBulkAnalyzerDiagnosticConfiguration(DiagnosticSever dotnet_analyzer_diagnostic.category-{category}.severity = error"; TestBulkAnalyzerConfigurationCore(analyzer, analyzerConfigText, errorlog, expectedDiagnosticSeverity: ReportDiagnostic.Warn); + // Verify category based configuration to warning + /warnaserror reports errors. + analyzerConfigText = $@" +[*.cs] +dotnet_analyzer_diagnostic.category-{category}.severity = warning"; + TestBulkAnalyzerConfigurationCore(analyzer, analyzerConfigText, errorlog, warnAsError: true, expectedDiagnosticSeverity: ReportDiagnostic.Error); // Verify disabled by default analyzer is not enabled by category based configuration. analyzer = new NamedTypeAnalyzerWithConfigurableEnabledByDefault(isEnabledByDefault: false, defaultSeverity); @@ -12577,6 +12588,12 @@ public void TestBulkAnalyzerDiagnosticConfiguration(DiagnosticSeverity defaultSe dotnet_analyzer_diagnostic.severity = error"; TestBulkAnalyzerConfigurationCore(analyzer, analyzerConfigText, errorlog, expectedDiagnosticSeverity: ReportDiagnostic.Warn); + // Verify bulk configuration to warning + /warnaserror reports errors. + analyzerConfigText = $@" +[*.cs] +dotnet_analyzer_diagnostic.severity = warning"; + TestBulkAnalyzerConfigurationCore(analyzer, analyzerConfigText, errorlog, warnAsError: true, expectedDiagnosticSeverity: ReportDiagnostic.Error); + // Verify disabled by default analyzer is not enabled by bulk configuration. analyzer = new NamedTypeAnalyzerWithConfigurableEnabledByDefault(isEnabledByDefault: false, defaultSeverity); analyzerConfigText = $@" @@ -12654,7 +12671,8 @@ private void TestBulkAnalyzerConfigurationCore( bool errorlog, ReportDiagnostic expectedDiagnosticSeverity, string rulesetText = null, - bool noWarn = false) + bool noWarn = false, + bool warnAsError = false) { var diagnosticId = analyzer.Descriptor.Id; var dir = Temp.CreateDirectory(); @@ -12672,6 +12690,11 @@ private void TestBulkAnalyzerConfigurationCore( arguments = arguments.Append($"/nowarn:{diagnosticId}"); } + if (warnAsError) + { + arguments = arguments.Append($"/warnaserror"); + } + if (errorlog) { arguments = arguments.Append($"/errorlog:errorlog"); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 33bdb13a7ccad..0781f26060308 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -11,6 +11,7 @@ using System.Text; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -129,6 +130,11 @@ private static void VerifyMissingType(string source, WellKnownType type, params comp.VerifyEmitDiagnostics(expected); } + // Instrumentation to investigate CI failure: https://github.com/dotnet/roslyn/issues/34207 + private CSharpCompilation CreateCompilationWithAsyncIterator(string source, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null) + => CreateCompilationWithTasksExtensions(new[] { (CSharpTestSource)CSharpTestBase.Parse(source, filename: "source", parseOptions), CSharpTestBase.Parse(AsyncStreamsTypes, filename: "AsyncStreamsTypes", parseOptions) }, + options: options, parseOptions: parseOptions); + private CSharpCompilation CreateCompilationWithAsyncIterator(CSharpTestSource source, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null) => CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, options: options, parseOptions: parseOptions); @@ -170,7 +176,7 @@ public static async Task Main() var v = CompileAndVerify(comp, expectedOutput: "hello world"); v.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 240 (0xf0) + // Code size 254 (0xfe) .maxstack 3 .locals init (int V_0, System.Exception V_1) @@ -187,7 +193,7 @@ .locals init (int V_0, IL_0010: ldarg.0 IL_0011: ldfld ""bool C.d__1.<>w__disposeMode"" IL_0016: brfalse.s IL_001d - IL_0018: leave IL_00cd + IL_0018: leave IL_00d4 IL_001d: ldarg.0 IL_001e: ldc.i4.m1 IL_001f: dup @@ -255,11 +261,11 @@ .locals init (int V_0, IL_0096: ldarg.0 IL_0097: ldfld ""bool C.d__1.<>w__disposeMode"" IL_009c: brfalse.s IL_00a0 - IL_009e: leave.s IL_00cd + IL_009e: leave.s IL_00d4 IL_00a0: ldarg.0 IL_00a1: ldc.i4.1 IL_00a2: stfld ""bool C.d__1.<>w__disposeMode"" - IL_00a7: leave.s IL_00cd + IL_00a7: leave.s IL_00d4 } catch System.Exception { @@ -268,30 +274,36 @@ .locals init (int V_0, IL_00ab: ldc.i4.s -2 IL_00ad: stfld ""int C.d__1.<>1__state"" IL_00b2: ldarg.0 - IL_00b3: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__1.<>t__builder"" - IL_00b8: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_00bd: nop - IL_00be: ldarg.0 - IL_00bf: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__1.<>v__promiseOfValueOrEnd"" - IL_00c4: ldloc.1 - IL_00c5: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_00ca: nop - IL_00cb: leave.s IL_00ef + IL_00b3: ldnull + IL_00b4: stfld ""string C.d__1.<>2__current"" + IL_00b9: ldarg.0 + IL_00ba: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__1.<>t__builder"" + IL_00bf: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_00c4: nop + IL_00c5: ldarg.0 + IL_00c6: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__1.<>v__promiseOfValueOrEnd"" + IL_00cb: ldloc.1 + IL_00cc: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_00d1: nop + IL_00d2: leave.s IL_00fd } - IL_00cd: ldarg.0 - IL_00ce: ldc.i4.s -2 - IL_00d0: stfld ""int C.d__1.<>1__state"" - IL_00d5: ldarg.0 - IL_00d6: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__1.<>t__builder"" - IL_00db: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_00e0: nop - IL_00e1: ldarg.0 - IL_00e2: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__1.<>v__promiseOfValueOrEnd"" - IL_00e7: ldc.i4.0 - IL_00e8: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_00ed: nop - IL_00ee: ret - IL_00ef: ret + IL_00d4: ldarg.0 + IL_00d5: ldc.i4.s -2 + IL_00d7: stfld ""int C.d__1.<>1__state"" + IL_00dc: ldarg.0 + IL_00dd: ldnull + IL_00de: stfld ""string C.d__1.<>2__current"" + IL_00e3: ldarg.0 + IL_00e4: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__1.<>t__builder"" + IL_00e9: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_00ee: nop + IL_00ef: ldarg.0 + IL_00f0: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__1.<>v__promiseOfValueOrEnd"" + IL_00f5: ldc.i4.0 + IL_00f6: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_00fb: nop + IL_00fc: ret + IL_00fd: ret }"); } @@ -337,7 +349,7 @@ public static async Task Main() var v = CompileAndVerify(comp, expectedOutput: "hello world!"); v.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 181 (0xb5) + // Code size 195 (0xc3) .maxstack 3 .locals init (int V_0, System.Exception V_1) @@ -354,7 +366,7 @@ .locals init (int V_0, IL_0010: ldarg.0 IL_0011: ldfld ""bool C.d__0.<>w__disposeMode"" IL_0016: brfalse.s IL_001a - IL_0018: leave.s IL_0092 + IL_0018: leave.s IL_0099 IL_001a: ldarg.0 IL_001b: ldc.i4.m1 IL_001c: dup @@ -403,11 +415,11 @@ .locals init (int V_0, IL_005b: ldarg.0 IL_005c: ldfld ""bool C.d__0.<>w__disposeMode"" IL_0061: brfalse.s IL_0065 - IL_0063: leave.s IL_0092 + IL_0063: leave.s IL_0099 IL_0065: ldarg.0 IL_0066: ldc.i4.1 IL_0067: stfld ""bool C.d__0.<>w__disposeMode"" - IL_006c: leave.s IL_0092 + IL_006c: leave.s IL_0099 } catch System.Exception { @@ -416,30 +428,36 @@ .locals init (int V_0, IL_0070: ldc.i4.s -2 IL_0072: stfld ""int C.d__0.<>1__state"" IL_0077: ldarg.0 - IL_0078: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_007d: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_0082: nop - IL_0083: ldarg.0 - IL_0084: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_0089: ldloc.1 - IL_008a: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_008f: nop - IL_0090: leave.s IL_00b4 + IL_0078: ldnull + IL_0079: stfld ""string C.d__0.<>2__current"" + IL_007e: ldarg.0 + IL_007f: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0084: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0089: nop + IL_008a: ldarg.0 + IL_008b: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0090: ldloc.1 + IL_0091: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0096: nop + IL_0097: leave.s IL_00c2 } - IL_0092: ldarg.0 - IL_0093: ldc.i4.s -2 - IL_0095: stfld ""int C.d__0.<>1__state"" - IL_009a: ldarg.0 - IL_009b: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_00a0: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_00a5: nop - IL_00a6: ldarg.0 - IL_00a7: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_00ac: ldc.i4.0 - IL_00ad: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_00b2: nop - IL_00b3: ret - IL_00b4: ret + IL_0099: ldarg.0 + IL_009a: ldc.i4.s -2 + IL_009c: stfld ""int C.d__0.<>1__state"" + IL_00a1: ldarg.0 + IL_00a2: ldnull + IL_00a3: stfld ""string C.d__0.<>2__current"" + IL_00a8: ldarg.0 + IL_00a9: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00ae: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_00b3: nop + IL_00b4: ldarg.0 + IL_00b5: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_00ba: ldc.i4.0 + IL_00bb: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_00c0: nop + IL_00c1: ret + IL_00c2: ret }"); } @@ -2563,7 +2581,7 @@ .maxstack 5 { verifier.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"{ - // Code size 322 (0x142) + // Code size 336 (0x150) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -2592,7 +2610,7 @@ .locals init (int V_0, IL_002f: ldarg.0 IL_0030: ldfld ""bool C.d__0.<>w__disposeMode"" IL_0035: brfalse.s IL_003c - IL_0037: leave IL_0112 + IL_0037: leave IL_0119 IL_003c: ldarg.0 IL_003d: ldc.i4.m1 IL_003e: dup @@ -2629,7 +2647,7 @@ .locals init (int V_0, IL_007f: ldloca.s V_2 IL_0081: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" IL_0086: nop - IL_0087: leave IL_0141 + IL_0087: leave IL_014f // async: resume IL_008c: ldarg.0 IL_008d: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" @@ -2658,7 +2676,7 @@ .locals init (int V_0, IL_00c5: dup IL_00c6: stloc.0 IL_00c7: stfld ""int C.d__0.<>1__state"" - IL_00cc: leave.s IL_0134 + IL_00cc: leave.s IL_0142 // sequence point: IL_00ce: ldarg.0 IL_00cf: ldc.i4.m1 @@ -2668,12 +2686,12 @@ .locals init (int V_0, IL_00d7: ldarg.0 IL_00d8: ldfld ""bool C.d__0.<>w__disposeMode"" IL_00dd: brfalse.s IL_00e1 - IL_00df: leave.s IL_0112 + IL_00df: leave.s IL_0119 // sequence point: Write("" 4 ""); IL_00e1: ldstr "" 4 "" IL_00e6: call ""void System.Console.Write(string)"" IL_00eb: nop - IL_00ec: leave.s IL_0112 + IL_00ec: leave.s IL_0119 } catch System.Exception { @@ -2683,44 +2701,50 @@ .locals init (int V_0, IL_00f0: ldc.i4.s -2 IL_00f2: stfld ""int C.d__0.<>1__state"" IL_00f7: ldarg.0 - IL_00f8: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_00fd: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_0102: nop - IL_0103: ldarg.0 - IL_0104: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_0109: ldloc.3 - IL_010a: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_010f: nop - IL_0110: leave.s IL_0141 + IL_00f8: ldc.i4.0 + IL_00f9: stfld ""int C.d__0.<>2__current"" + IL_00fe: ldarg.0 + IL_00ff: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0104: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0109: nop + IL_010a: ldarg.0 + IL_010b: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0110: ldloc.3 + IL_0111: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0116: nop + IL_0117: leave.s IL_014f } // sequence point: } - IL_0112: ldarg.0 - IL_0113: ldc.i4.s -2 - IL_0115: stfld ""int C.d__0.<>1__state"" + IL_0119: ldarg.0 + IL_011a: ldc.i4.s -2 + IL_011c: stfld ""int C.d__0.<>1__state"" // sequence point: - IL_011a: ldarg.0 - IL_011b: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_0120: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_0125: nop - IL_0126: ldarg.0 - IL_0127: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_012c: ldc.i4.0 - IL_012d: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_0132: nop - IL_0133: ret + IL_0121: ldarg.0 + IL_0122: ldc.i4.0 + IL_0123: stfld ""int C.d__0.<>2__current"" + IL_0128: ldarg.0 + IL_0129: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_012e: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0133: nop IL_0134: ldarg.0 IL_0135: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_013a: ldc.i4.1 + IL_013a: ldc.i4.0 IL_013b: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" IL_0140: nop IL_0141: ret + IL_0142: ldarg.0 + IL_0143: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0148: ldc.i4.1 + IL_0149: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_014e: nop + IL_014f: ret }", sequencePoints: "C+d__0.MoveNext", source: source); } else { verifier.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 300 (0x12c) + // Code size 314 (0x13a) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -2745,7 +2769,7 @@ .locals init (int V_0, IL_0024: ldarg.0 IL_0025: ldfld ""bool C.d__0.<>w__disposeMode"" IL_002a: brfalse.s IL_0031 - IL_002c: leave IL_00ff + IL_002c: leave IL_0106 IL_0031: ldarg.0 IL_0032: ldc.i4.m1 IL_0033: dup @@ -2778,7 +2802,7 @@ .locals init (int V_0, IL_0070: ldloca.s V_1 IL_0072: ldloca.s V_2 IL_0074: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" - IL_0079: leave IL_012b + IL_0079: leave IL_0139 // async: resume IL_007e: ldarg.0 IL_007f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" @@ -2805,7 +2829,7 @@ .locals init (int V_0, IL_00b5: dup IL_00b6: stloc.0 IL_00b7: stfld ""int C.d__0.<>1__state"" - IL_00bc: leave.s IL_011f + IL_00bc: leave.s IL_012d // sequence point: IL_00be: ldarg.0 IL_00bf: ldc.i4.m1 @@ -2815,11 +2839,11 @@ .locals init (int V_0, IL_00c7: ldarg.0 IL_00c8: ldfld ""bool C.d__0.<>w__disposeMode"" IL_00cd: brfalse.s IL_00d1 - IL_00cf: leave.s IL_00ff + IL_00cf: leave.s IL_0106 // sequence point: Write("" 4 ""); IL_00d1: ldstr "" 4 "" IL_00d6: call ""void System.Console.Write(string)"" - IL_00db: leave.s IL_00ff + IL_00db: leave.s IL_0106 } catch System.Exception { @@ -2829,32 +2853,38 @@ .locals init (int V_0, IL_00df: ldc.i4.s -2 IL_00e1: stfld ""int C.d__0.<>1__state"" IL_00e6: ldarg.0 - IL_00e7: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_00ec: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_00f1: ldarg.0 - IL_00f2: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_00f7: ldloc.3 - IL_00f8: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_00fd: leave.s IL_012b + IL_00e7: ldc.i4.0 + IL_00e8: stfld ""int C.d__0.<>2__current"" + IL_00ed: ldarg.0 + IL_00ee: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00f3: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_00f8: ldarg.0 + IL_00f9: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_00fe: ldloc.3 + IL_00ff: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0104: leave.s IL_0139 } // sequence point: } - IL_00ff: ldarg.0 - IL_0100: ldc.i4.s -2 - IL_0102: stfld ""int C.d__0.<>1__state"" + IL_0106: ldarg.0 + IL_0107: ldc.i4.s -2 + IL_0109: stfld ""int C.d__0.<>1__state"" // sequence point: - IL_0107: ldarg.0 - IL_0108: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_010d: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_0112: ldarg.0 - IL_0113: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_0118: ldc.i4.0 - IL_0119: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_011e: ret - IL_011f: ldarg.0 - IL_0120: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_0125: ldc.i4.1 - IL_0126: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_012b: ret + IL_010e: ldarg.0 + IL_010f: ldc.i4.0 + IL_0110: stfld ""int C.d__0.<>2__current"" + IL_0115: ldarg.0 + IL_0116: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_011b: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0120: ldarg.0 + IL_0121: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0126: ldc.i4.0 + IL_0127: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_012c: ret + IL_012d: ldarg.0 + IL_012e: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0133: ldc.i4.1 + IL_0134: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0139: ret }", sequencePoints: "C+d__0.MoveNext", source: source); } } @@ -2968,7 +2998,7 @@ .locals init (C.d__0 V_0, // we generate disposal logic for the combinedTokens field verifier.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 329 (0x149) + // Code size 343 (0x157) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -2993,7 +3023,7 @@ .locals init (int V_0, IL_0024: ldarg.0 IL_0025: ldfld ""bool C.d__0.<>w__disposeMode"" IL_002a: brfalse.s IL_0031 - IL_002c: leave IL_0102 + IL_002c: leave IL_0109 IL_0031: ldarg.0 IL_0032: ldc.i4.m1 IL_0033: dup @@ -3027,7 +3057,7 @@ .locals init (int V_0, IL_006d: ldloca.s V_1 IL_006f: ldloca.s V_2 IL_0071: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" - IL_0076: leave IL_0148 + IL_0076: leave IL_0156 // async: resume IL_007b: ldarg.0 IL_007c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" @@ -3051,7 +3081,7 @@ .locals init (int V_0, IL_00a8: dup IL_00a9: stloc.0 IL_00aa: stfld ""int C.d__0.<>1__state"" - IL_00af: leave IL_013c + IL_00af: leave IL_014a // sequence point: IL_00b4: ldarg.0 IL_00b5: ldc.i4.m1 @@ -3062,7 +3092,7 @@ .locals init (int V_0, IL_00be: ldfld ""bool C.d__0.<>w__disposeMode"" IL_00c3: pop // sequence point: - IL_00c4: leave.s IL_0102 + IL_00c4: leave.s IL_0109 } catch System.Exception { @@ -3081,41 +3111,47 @@ .locals init (int V_0, IL_00e3: ldnull IL_00e4: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" IL_00e9: ldarg.0 - IL_00ea: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_00ef: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_00f4: ldarg.0 - IL_00f5: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_00fa: ldloc.3 - IL_00fb: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_0100: leave.s IL_0148 + IL_00ea: ldc.i4.0 + IL_00eb: stfld ""int C.d__0.<>2__current"" + IL_00f0: ldarg.0 + IL_00f1: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00f6: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_00fb: ldarg.0 + IL_00fc: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0101: ldloc.3 + IL_0102: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0107: leave.s IL_0156 } // sequence point: } - IL_0102: ldarg.0 - IL_0103: ldc.i4.s -2 - IL_0105: stfld ""int C.d__0.<>1__state"" + IL_0109: ldarg.0 + IL_010a: ldc.i4.s -2 + IL_010c: stfld ""int C.d__0.<>1__state"" // sequence point: - IL_010a: ldarg.0 - IL_010b: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" - IL_0110: brfalse.s IL_0124 - IL_0112: ldarg.0 - IL_0113: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" - IL_0118: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" - IL_011d: ldarg.0 - IL_011e: ldnull - IL_011f: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0111: ldarg.0 + IL_0112: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0117: brfalse.s IL_012b + IL_0119: ldarg.0 + IL_011a: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_011f: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" IL_0124: ldarg.0 - IL_0125: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_012a: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_012f: ldarg.0 - IL_0130: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_0135: ldc.i4.0 - IL_0136: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_013b: ret - IL_013c: ldarg.0 - IL_013d: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_0142: ldc.i4.1 - IL_0143: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_0148: ret + IL_0125: ldnull + IL_0126: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_012b: ldarg.0 + IL_012c: ldc.i4.0 + IL_012d: stfld ""int C.d__0.<>2__current"" + IL_0132: ldarg.0 + IL_0133: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0138: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_013d: ldarg.0 + IL_013e: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0143: ldc.i4.0 + IL_0144: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0149: ret + IL_014a: ldarg.0 + IL_014b: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0150: ldc.i4.1 + IL_0151: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0156: ret }", sequencePoints: "C+d__0.MoveNext", source: source); } @@ -3230,7 +3266,7 @@ .locals init (C.d__0 V_0, // we generate disposal logic for the combinedTokens field verifier.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 329 (0x149) + // Code size 343 (0x157) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -3255,7 +3291,7 @@ .locals init (int V_0, IL_0024: ldarg.0 IL_0025: ldfld ""bool C.d__0.<>w__disposeMode"" IL_002a: brfalse.s IL_0031 - IL_002c: leave IL_0102 + IL_002c: leave IL_0109 IL_0031: ldarg.0 IL_0032: ldc.i4.m1 IL_0033: dup @@ -3289,7 +3325,7 @@ .locals init (int V_0, IL_006d: ldloca.s V_1 IL_006f: ldloca.s V_2 IL_0071: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" - IL_0076: leave IL_0148 + IL_0076: leave IL_0156 // async: resume IL_007b: ldarg.0 IL_007c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" @@ -3313,7 +3349,7 @@ .locals init (int V_0, IL_00a8: dup IL_00a9: stloc.0 IL_00aa: stfld ""int C.d__0.<>1__state"" - IL_00af: leave IL_013c + IL_00af: leave IL_014a // sequence point: IL_00b4: ldarg.0 IL_00b5: ldc.i4.m1 @@ -3324,7 +3360,7 @@ .locals init (int V_0, IL_00be: ldfld ""bool C.d__0.<>w__disposeMode"" IL_00c3: pop // sequence point: - IL_00c4: leave.s IL_0102 + IL_00c4: leave.s IL_0109 } catch System.Exception { @@ -3343,41 +3379,47 @@ .locals init (int V_0, IL_00e3: ldnull IL_00e4: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" IL_00e9: ldarg.0 - IL_00ea: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_00ef: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_00f4: ldarg.0 - IL_00f5: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_00fa: ldloc.3 - IL_00fb: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_0100: leave.s IL_0148 + IL_00ea: ldc.i4.0 + IL_00eb: stfld ""int C.d__0.<>2__current"" + IL_00f0: ldarg.0 + IL_00f1: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00f6: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_00fb: ldarg.0 + IL_00fc: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0101: ldloc.3 + IL_0102: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0107: leave.s IL_0156 } // sequence point: } - IL_0102: ldarg.0 - IL_0103: ldc.i4.s -2 - IL_0105: stfld ""int C.d__0.<>1__state"" + IL_0109: ldarg.0 + IL_010a: ldc.i4.s -2 + IL_010c: stfld ""int C.d__0.<>1__state"" // sequence point: - IL_010a: ldarg.0 - IL_010b: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" - IL_0110: brfalse.s IL_0124 - IL_0112: ldarg.0 - IL_0113: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" - IL_0118: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" - IL_011d: ldarg.0 - IL_011e: ldnull - IL_011f: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0111: ldarg.0 + IL_0112: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0117: brfalse.s IL_012b + IL_0119: ldarg.0 + IL_011a: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_011f: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" IL_0124: ldarg.0 - IL_0125: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_012a: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_012f: ldarg.0 - IL_0130: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_0135: ldc.i4.0 - IL_0136: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_013b: ret - IL_013c: ldarg.0 - IL_013d: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_0142: ldc.i4.1 - IL_0143: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_0148: ret + IL_0125: ldnull + IL_0126: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_012b: ldarg.0 + IL_012c: ldc.i4.0 + IL_012d: stfld ""int C.d__0.<>2__current"" + IL_0132: ldarg.0 + IL_0133: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0138: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_013d: ldarg.0 + IL_013e: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0143: ldc.i4.0 + IL_0144: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0149: ret + IL_014a: ldarg.0 + IL_014b: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0150: ldc.i4.1 + IL_0151: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0156: ret }", sequencePoints: "C+d__0.MoveNext", source: source); } @@ -3493,7 +3535,7 @@ .locals init (C.<g__local|0_0>d V_0, // we generate disposal logic for the combinedTokens field verifier.VerifyIL("C.<g__local|0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 329 (0x149) + // Code size 343 (0x157) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -3518,7 +3560,7 @@ .locals init (int V_0, IL_0024: ldarg.0 IL_0025: ldfld ""bool C.<g__local|0_0>d.<>w__disposeMode"" IL_002a: brfalse.s IL_0031 - IL_002c: leave IL_0102 + IL_002c: leave IL_0109 IL_0031: ldarg.0 IL_0032: ldc.i4.m1 IL_0033: dup @@ -3552,7 +3594,7 @@ .locals init (int V_0, IL_006d: ldloca.s V_1 IL_006f: ldloca.s V_2 IL_0071: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompletedg__local|0_0>d>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.<g__local|0_0>d)"" - IL_0076: leave IL_0148 + IL_0076: leave IL_0156 // async: resume IL_007b: ldarg.0 IL_007c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.<g__local|0_0>d.<>u__1"" @@ -3576,7 +3618,7 @@ .locals init (int V_0, IL_00a8: dup IL_00a9: stloc.0 IL_00aa: stfld ""int C.<g__local|0_0>d.<>1__state"" - IL_00af: leave IL_013c + IL_00af: leave IL_014a // sequence point: IL_00b4: ldarg.0 IL_00b5: ldc.i4.m1 @@ -3587,7 +3629,7 @@ .locals init (int V_0, IL_00be: ldfld ""bool C.<g__local|0_0>d.<>w__disposeMode"" IL_00c3: pop // sequence point: - IL_00c4: leave.s IL_0102 + IL_00c4: leave.s IL_0109 } catch System.Exception { @@ -3606,41 +3648,47 @@ .locals init (int V_0, IL_00e3: ldnull IL_00e4: stfld ""System.Threading.CancellationTokenSource C.<g__local|0_0>d.<>x__combinedTokens"" IL_00e9: ldarg.0 - IL_00ea: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<g__local|0_0>d.<>t__builder"" - IL_00ef: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_00f4: ldarg.0 - IL_00f5: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.<g__local|0_0>d.<>v__promiseOfValueOrEnd"" - IL_00fa: ldloc.3 - IL_00fb: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_0100: leave.s IL_0148 + IL_00ea: ldc.i4.0 + IL_00eb: stfld ""int C.<g__local|0_0>d.<>2__current"" + IL_00f0: ldarg.0 + IL_00f1: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<g__local|0_0>d.<>t__builder"" + IL_00f6: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_00fb: ldarg.0 + IL_00fc: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.<g__local|0_0>d.<>v__promiseOfValueOrEnd"" + IL_0101: ldloc.3 + IL_0102: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0107: leave.s IL_0156 } // sequence point: } - IL_0102: ldarg.0 - IL_0103: ldc.i4.s -2 - IL_0105: stfld ""int C.<g__local|0_0>d.<>1__state"" + IL_0109: ldarg.0 + IL_010a: ldc.i4.s -2 + IL_010c: stfld ""int C.<g__local|0_0>d.<>1__state"" // sequence point: - IL_010a: ldarg.0 - IL_010b: ldfld ""System.Threading.CancellationTokenSource C.<g__local|0_0>d.<>x__combinedTokens"" - IL_0110: brfalse.s IL_0124 - IL_0112: ldarg.0 - IL_0113: ldfld ""System.Threading.CancellationTokenSource C.<g__local|0_0>d.<>x__combinedTokens"" - IL_0118: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" - IL_011d: ldarg.0 - IL_011e: ldnull - IL_011f: stfld ""System.Threading.CancellationTokenSource C.<g__local|0_0>d.<>x__combinedTokens"" + IL_0111: ldarg.0 + IL_0112: ldfld ""System.Threading.CancellationTokenSource C.<g__local|0_0>d.<>x__combinedTokens"" + IL_0117: brfalse.s IL_012b + IL_0119: ldarg.0 + IL_011a: ldfld ""System.Threading.CancellationTokenSource C.<g__local|0_0>d.<>x__combinedTokens"" + IL_011f: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" IL_0124: ldarg.0 - IL_0125: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<g__local|0_0>d.<>t__builder"" - IL_012a: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_012f: ldarg.0 - IL_0130: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.<g__local|0_0>d.<>v__promiseOfValueOrEnd"" - IL_0135: ldc.i4.0 - IL_0136: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_013b: ret - IL_013c: ldarg.0 - IL_013d: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.<g__local|0_0>d.<>v__promiseOfValueOrEnd"" - IL_0142: ldc.i4.1 - IL_0143: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_0148: ret + IL_0125: ldnull + IL_0126: stfld ""System.Threading.CancellationTokenSource C.<g__local|0_0>d.<>x__combinedTokens"" + IL_012b: ldarg.0 + IL_012c: ldc.i4.0 + IL_012d: stfld ""int C.<g__local|0_0>d.<>2__current"" + IL_0132: ldarg.0 + IL_0133: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.<g__local|0_0>d.<>t__builder"" + IL_0138: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_013d: ldarg.0 + IL_013e: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.<g__local|0_0>d.<>v__promiseOfValueOrEnd"" + IL_0143: ldc.i4.0 + IL_0144: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0149: ret + IL_014a: ldarg.0 + IL_014b: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.<g__local|0_0>d.<>v__promiseOfValueOrEnd"" + IL_0150: ldc.i4.1 + IL_0151: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0156: ret }", sequencePoints: "C+<g__local|0_0>d.MoveNext", source: source); } @@ -3710,7 +3758,7 @@ .locals init (C.d__0 V_0) // we generate disposal logic for the combinedTokens field verifier.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 322 (0x142) + // Code size 336 (0x150) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -3735,7 +3783,7 @@ .locals init (int V_0, IL_0024: ldarg.0 IL_0025: ldfld ""bool C.d__0.<>w__disposeMode"" IL_002a: brfalse.s IL_0031 - IL_002c: leave IL_00fb + IL_002c: leave IL_0102 IL_0031: ldarg.0 IL_0032: ldc.i4.m1 IL_0033: dup @@ -3765,7 +3813,7 @@ .locals init (int V_0, IL_0066: ldloca.s V_1 IL_0068: ldloca.s V_2 IL_006a: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" - IL_006f: leave IL_0141 + IL_006f: leave IL_014f // async: resume IL_0074: ldarg.0 IL_0075: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" @@ -3789,7 +3837,7 @@ .locals init (int V_0, IL_00a1: dup IL_00a2: stloc.0 IL_00a3: stfld ""int C.d__0.<>1__state"" - IL_00a8: leave IL_0135 + IL_00a8: leave IL_0143 // sequence point: IL_00ad: ldarg.0 IL_00ae: ldc.i4.m1 @@ -3800,7 +3848,7 @@ .locals init (int V_0, IL_00b7: ldfld ""bool C.d__0.<>w__disposeMode"" IL_00bc: pop // sequence point: - IL_00bd: leave.s IL_00fb + IL_00bd: leave.s IL_0102 } catch System.Exception { @@ -3819,41 +3867,47 @@ .locals init (int V_0, IL_00dc: ldnull IL_00dd: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" IL_00e2: ldarg.0 - IL_00e3: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_00e8: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_00ed: ldarg.0 - IL_00ee: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_00f3: ldloc.3 - IL_00f4: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_00f9: leave.s IL_0141 + IL_00e3: ldc.i4.0 + IL_00e4: stfld ""int C.d__0.<>2__current"" + IL_00e9: ldarg.0 + IL_00ea: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00ef: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_00f4: ldarg.0 + IL_00f5: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_00fa: ldloc.3 + IL_00fb: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0100: leave.s IL_014f } // sequence point: } - IL_00fb: ldarg.0 - IL_00fc: ldc.i4.s -2 - IL_00fe: stfld ""int C.d__0.<>1__state"" + IL_0102: ldarg.0 + IL_0103: ldc.i4.s -2 + IL_0105: stfld ""int C.d__0.<>1__state"" // sequence point: - IL_0103: ldarg.0 - IL_0104: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" - IL_0109: brfalse.s IL_011d - IL_010b: ldarg.0 - IL_010c: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" - IL_0111: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" - IL_0116: ldarg.0 - IL_0117: ldnull - IL_0118: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_010a: ldarg.0 + IL_010b: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0110: brfalse.s IL_0124 + IL_0112: ldarg.0 + IL_0113: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0118: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" IL_011d: ldarg.0 - IL_011e: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_0123: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_0128: ldarg.0 - IL_0129: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_012e: ldc.i4.0 - IL_012f: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_0134: ret - IL_0135: ldarg.0 - IL_0136: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_013b: ldc.i4.1 - IL_013c: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_0141: ret + IL_011e: ldnull + IL_011f: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0124: ldarg.0 + IL_0125: ldc.i4.0 + IL_0126: stfld ""int C.d__0.<>2__current"" + IL_012b: ldarg.0 + IL_012c: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0131: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0136: ldarg.0 + IL_0137: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_013c: ldc.i4.0 + IL_013d: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0142: ret + IL_0143: ldarg.0 + IL_0144: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0149: ldc.i4.1 + IL_014a: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_014f: ret }", sequencePoints: "C+d__0.MoveNext", source: source); } @@ -7981,5 +8035,150 @@ public static async Task Main() var v = CompileAndVerify(comp, expectedOutput: "BEFORE INSIDE INSIDE2 AFTER"); v.VerifyDiagnostics(); } + + [Fact, WorkItem(58444, "https://github.com/dotnet/roslyn/issues/58444")] + public void ClearCurrentOnRegularExit() + { + var source = @" +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +var r = new AsyncReader(); +var enumerator = r.GetAsyncEnumerator(); +try +{ + while (await enumerator.MoveNextAsync()) + { + System.Console.Write(""RAN ""); + } + + if (enumerator.Current is null) + { + System.Console.Write(""CLEARED""); + } +} +finally +{ + await enumerator.DisposeAsync(); +} + +class AsyncReader : IAsyncEnumerable +{ + public async IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + { + await Task.Yield(); + yield return new object(); + await Task.Yield(); + yield return new object(); + await Task.Yield(); + yield return new object(); + } +} +"; + var comp = CreateCompilationWithAsyncIterator(source); + CompileAndVerify(comp, expectedOutput: "RAN RAN RAN CLEARED"); + } + + [Fact, WorkItem(58444, "https://github.com/dotnet/roslyn/issues/58444")] + public void ClearCurrentOnException() + { + var source = @" +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +var r = new AsyncReader(); +var enumerator = r.GetAsyncEnumerator(); +try +{ + try + { + while (await enumerator.MoveNextAsync()) + { + Console.Write(""RAN ""); + } + } + catch (System.Exception e) + { + Console.Write(e.Message); + } + + if (enumerator.Current is null) + { + Console.Write(""CLEARED""); + } +} +finally +{ + await enumerator.DisposeAsync(); +} + +class AsyncReader : IAsyncEnumerable +{ + public async IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + { + await Task.Yield(); + yield return new object(); + await Task.Yield(); + yield return new object(); + await Task.Yield(); + throw new Exception(""EXCEPTION ""); + } +} +"; + var comp = CreateCompilationWithAsyncIterator(source); + CompileAndVerify(comp, expectedOutput: "RAN RAN EXCEPTION CLEARED"); + } + + [Fact, WorkItem(58444, "https://github.com/dotnet/roslyn/issues/58444")] + public void ClearCurrentOnRegularExit_Generic() + { + var source = @" +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +var r = new AsyncReader() { value = 42 }; +var enumerator = r.GetAsyncEnumerator(); +try +{ + while (await enumerator.MoveNextAsync()) + { + if (enumerator.Current is 42) + System.Console.Write(""RAN ""); + } + + if (enumerator.Current is 0) + System.Console.Write(""CLEARED""); +} +finally +{ + await enumerator.DisposeAsync(); +} + +class AsyncReader : IAsyncEnumerable +{ + public T value; + public async IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + { + await Task.Yield(); + yield return value; + await Task.Yield(); + yield return value; + await Task.Yield(); + yield return value; + } +} +"; + var comp = CreateCompilationWithAsyncIterator(source); + CompileAndVerify(comp, expectedOutput: "RAN RAN RAN CLEARED"); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs index baf85196a56ef..5c0f881569023 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs @@ -6161,7 +6161,7 @@ public static async IAsyncEnumerator GetAsyncEnumerator(this Range range) options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); - CompileAndVerify(comp, expectedOutput: "123"); + CompileAndVerify(comp, expectedOutput: "123", verify: Verification.FailsILVerify); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs index 2df99e3bcab0f..3daeccaa04c99 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs @@ -1102,7 +1102,7 @@ static int M() return 0; } }"; - var comp = CompileAndVerify(source); + var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs index 2fb646126d46b..b465d43b10ca1 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs @@ -7614,7 +7614,7 @@ static void Main() } [Fact] - void InvokeVarForLvalueInParens() + public void InvokeVarForLvalueInParens() { var source = @" class Program diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs index ddc6a79b2f120..9b17e3e838e61 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs @@ -9603,7 +9603,7 @@ .locals init (int V_0, //a IL_0066: callvirt ""void <>A{00000004}.Invoke(System.Runtime.CompilerServices.CallSite, ref int, object)"" IL_006b: ret } -"); +", verify: Verification.FailsILVerify); // ILVerify doesn't support TypedReference } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs index 5769b9b9b15c8..5c5fe23f13644 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs @@ -3117,9 +3117,10 @@ public static void Main() } }"; + // PEVerify: [ : Test::Main][mdToken=0x6000001][offset 0x00000009][found Native Int][expected unmanaged pointer] Unexpected type on the stack. var c = CompileAndVerifyUtil(text, options: TestOptions.UnsafeReleaseDll, - verify: Verification.Fails); + verify: Verification.FailsPEVerify); c.VerifyDiagnostics(); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenForEachTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenForEachTests.cs index 4ebd2028fb9b0..7d6b40bc72af5 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenForEachTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenForEachTests.cs @@ -1384,7 +1384,8 @@ ref struct DisposableEnumerator public bool MoveNext() { return ++x < 4; } public void Dispose() { System.Console.WriteLine(""Done with DisposableEnumerator""); } }"; - var compilation = CompileAndVerify(source, expectedOutput: @" + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + var compilation = CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: @" 1 2 3 @@ -1447,7 +1448,8 @@ ref struct DisposableEnumerator public bool MoveNext() { return ++x < 4; } public void Dispose(params object[] args) { System.Console.WriteLine($""Done with DisposableEnumerator. args was {args}, length {args.Length}""); } }"; - var compilation = CompileAndVerify(source, expectedOutput: @" + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + var compilation = CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: @" 1 2 3 @@ -1481,7 +1483,8 @@ ref struct DisposableEnumerator public bool MoveNext() { return ++x < 4; } public void Dispose(int arg = 1) { System.Console.WriteLine($""Done with DisposableEnumerator. arg was {arg}""); } }"; - var compilation = CompileAndVerify(source, expectedOutput: @" + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + var compilation = CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: @" 1 2 3 @@ -1521,7 +1524,8 @@ static class DisposeExtension } "; // extension methods do not contribute to disposal - CompileAndVerify(source, expectedOutput: @"123"); + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: @"123"); } [Fact] @@ -1561,7 +1565,8 @@ static class DisposeExtension2 } "; // extension methods do not contribute to disposal - CompileAndVerify(source, expectedOutput: @"123"); + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: @"123"); } [Fact] @@ -1597,7 +1602,8 @@ static class DisposeExtension } "; // extension methods do not contribute to disposal - CompileAndVerify(source, expectedOutput: @"123"); + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: @"123"); } [Fact] @@ -1633,7 +1639,8 @@ static class DisposeExtension } "; // extension methods do not contribute to disposal - CompileAndVerify(source, expectedOutput: @"123"); + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: @"123"); } [Fact] @@ -1729,7 +1736,8 @@ ref struct DisposableEnumerator public bool MoveNext() { return ++x < 4; } public void Dispose() { System.Console.WriteLine(""Done with DisposableEnumerator""); } }"; - var compilation = CompileAndVerify(source, parseOptions: TestOptions.Regular7_3, expectedOutput: @" + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + var compilation = CompileAndVerify(source, parseOptions: TestOptions.Regular7_3, verify: Verification.FailsILVerify, expectedOutput: @" 1 2 3"); @@ -4725,7 +4733,8 @@ ref struct Enumerator public bool MoveNext() => Current++ != 3; public void Dispose() { Console.Write(""Disposed""); } }"; - CompileAndVerify(source, parseOptions: TestOptions.Regular9, expectedOutput: @"123Disposed") + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + CompileAndVerify(source, parseOptions: TestOptions.Regular9, verify: Verification.FailsILVerify, expectedOutput: @"123Disposed") .VerifyIL("C.Main", @" { // Code size 45 (0x2d) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs index 45924d6644e79..dd613b96384d8 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs @@ -3982,7 +3982,8 @@ private void Test2(in int y, ref int f) var compilation = CreateCompilation(code, options: TestOptions.ReleaseExe); - var verifier = CompileAndVerify(compilation, expectedOutput: "0011", verify: Verification.Fails); + // PEVerify: Cannot change initonly field outside its .ctor. + var verifier = CompileAndVerify(compilation, expectedOutput: "0011", verify: Verification.FailsPEVerify); verifier.VerifyIL("Test..ctor()", @" { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIncrementTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIncrementTests.cs index e8db263011cda..2bf3cc671acbd 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIncrementTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIncrementTests.cs @@ -7,6 +7,7 @@ using System; using System.Globalization; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -1033,7 +1034,7 @@ public static void Main() } } "; - base.CompileAndVerify(source, expectedOutput: "12"). + base.CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: "12"). VerifyIL("Test.Main", @" { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs index 5b00142ccda9c..ffae592642cbb 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs @@ -2387,7 +2387,8 @@ public System.Collections.IEnumerable SomeNumbers() }"; // The compilation succeeds even though CompilerGeneratedAttribute and DebuggerNonUserCodeAttribute are not available. var compilation = CreateEmptyCompilation(new[] { Parse(source), Parse(corlib) }); - var verifier = CompileAndVerify(compilation, verify: Verification.Fails); + // PEVerify: System.Enum must extend System.ValueType. + var verifier = CompileAndVerify(compilation, verify: Verification.FailsPEVerify); verifier.VerifyDiagnostics( // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1)); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs index 9acbf01575d5e..f873d1ef0c65b 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs @@ -543,7 +543,7 @@ static partial void PM(int p2) } "; - CompileAndVerify(text).VerifyIL("Test.Main", @" + CompileAndVerify(text, parseOptions: TestOptions.Regular10).VerifyIL("Test.Main", @" { // Code size 36 (0x24) .maxstack 2 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenMscorlib.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenMscorlib.cs index e84776630d9aa..2ebf0906ce15c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenMscorlib.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenMscorlib.cs @@ -744,6 +744,12 @@ void Main() //IMPORTANT: we should NOT delegate E1.GetHashCode() to int.GetHashCode() // it is entirely possible that Enum.GetHashCode and int.GetHashCode // have different implementations + + // PEVerify: + // Error: Token 0x02000009 following ELEMENT_TYPE_CLASS (_VALUETYPE) in signature is a ValueType (Class,respectively). + // Error: Token 0x02000009 following ELEMENT_TYPE_CLASS(_VALUETYPE) in signature is a ValueType (Class, respectively). + // Type load failed. + // ILVerify: Failed to load type 'System.String' from assembly ... CompileAndVerify(comp, verify: Verification.Fails). VerifyIL("program.Main()", @" @@ -871,6 +877,8 @@ void Main() // but see the bug see VSW #396011, JIT needs references when loading // fields of certain clr-ambiguous structs (only possible when building mscorlib) + // PEVerify: Type load failed. + // ILVerify: Failed to load type 'System.String' from assembly ... CompileAndVerify(comp, verify: Verification.Fails). VerifyIL("System.IntPtr..ctor(int)", @" { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenNullCoalescingAssignmentTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenNullCoalescingAssignmentTests.cs index ceb9e3b2f4be8..0c30cfd082de4 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenNullCoalescingAssignmentTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenNullCoalescingAssignmentTests.cs @@ -703,7 +703,7 @@ public static void Main() } static void TestMethod() => Console.WriteLine(""In TestMethod""); } -", expectedOutput: @" +", parseOptions: TestOptions.Regular10, expectedOutput: @" In TestMethod In TestMethod ").VerifyIL("C.Main()", @" diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOverridingAndHiding.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOverridingAndHiding.cs index e013c7f76c9a1..985e7a6f2ccf5 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOverridingAndHiding.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenOverridingAndHiding.cs @@ -7,6 +7,7 @@ using System; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -2556,7 +2557,7 @@ public static void Main() // from assembly 'Dev10, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // is overriding a method that is not visible from that assembly. - CompileAndVerify(outerCompilation, verify: Verification.Fails).VerifyIL("Test.Main", @" + CompileAndVerify(outerCompilation, verify: Verification.FailsPEVerify).VerifyIL("Test.Main", @" { // Code size 65 (0x41) .maxstack 4 @@ -4121,13 +4122,31 @@ static void Main() if (isFromMetadata) { - WellKnownAttributesTestBase.VerifyParamArrayAttribute(parameterB); + VerifyParamArrayAttribute(parameterB); }; }; var verifier = CompileAndVerify(source, symbolValidator: validator(true), sourceSymbolValidator: validator(false), expectedOutput: @"System.Int32[]"); } + private static void VerifyParamArrayAttribute(ParameterSymbol parameter, bool expected = true) + { + Assert.Equal(expected, parameter.IsParams); + + var peParameter = (PEParameterSymbol)parameter; + var allAttributes = ((PEModuleSymbol)parameter.ContainingModule).GetCustomAttributesForToken(peParameter.Handle); + var paramArrayAttributes = allAttributes.Where(a => a.AttributeClass.ToTestDisplayString() == "System.ParamArrayAttribute"); + + if (expected) + { + Assert.Equal(1, paramArrayAttributes.Count()); + } + else + { + Assert.Empty(paramArrayAttributes); + } + } + [WorkItem(543158, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543158")] [Fact] public void XNoDefaultForParams_Dev10781558() diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadonlyStructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadonlyStructTests.cs index 11765060fecc6..179cdbc13fb3a 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadonlyStructTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadonlyStructTests.cs @@ -185,7 +185,7 @@ public override string ToString() } "; - var comp = CompileAndVerify(text, parseOptions: TestOptions.Regular, verify: Verification.Fails, expectedOutput: @"12"); + var comp = CompileAndVerify(text, parseOptions: TestOptions.Regular, verify: Verification.FailsPEVerify, expectedOutput: @"12"); comp.VerifyIL("Program.Main", @" { @@ -258,7 +258,8 @@ public override string ToString() } "; - var comp = CompileAndVerify(text, parseOptions: TestOptions.Regular, verify: Verification.Fails, expectedOutput: @"hello2"); + // PEVerify: Cannot change initonly field outside its .ctor. + var comp = CompileAndVerify(text, parseOptions: TestOptions.Regular, verify: Verification.FailsPEVerify, expectedOutput: @"hello2"); comp.VerifyIL("Program.Main", @" { @@ -338,7 +339,8 @@ static void Main() } "; - var comp = CompileAndVerify(text, new[] { ref1 }, parseOptions: TestOptions.Regular, verify: Verification.Fails, expectedOutput: @"hello2"); + // PEVerify: Cannot change initonly field outside its .ctor. + var comp = CompileAndVerify(text, new[] { ref1 }, parseOptions: TestOptions.Regular, verify: Verification.FailsPEVerify, expectedOutput: @"hello2"); comp.VerifyIL("Program.Main", @" { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs index 2c8ebf7061d4a..92b6ac0126c69 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs @@ -1060,7 +1060,8 @@ public static void RoExtension(in this S1 self) } "; - var comp = CompileAndVerifyWithMscorlib40(source, references: new[] { TestMetadata.Net40.System, ValueTupleRef, TestMetadata.Net40.SystemCore }, expectedOutput: "00", verify: Verification.Fails); + // PEVerify: Cannot change initonly field outside its .ctor. + var comp = CompileAndVerifyWithMscorlib40(source, references: new[] { TestMetadata.Net40.System, ValueTupleRef, TestMetadata.Net40.SystemCore }, expectedOutput: "00", verify: Verification.FailsPEVerify); comp.VerifyDiagnostics(); comp.VerifyIL("Program.Main", @" @@ -1147,8 +1148,8 @@ public override string ToString() } } "; - - var comp = CompileAndVerify(source, expectedOutput: "00", verify: Verification.Fails); + // PEVerify: Cannot change initonly field outside its .ctor. + var comp = CompileAndVerify(source, expectedOutput: "00", verify: Verification.FailsPEVerify); comp.VerifyDiagnostics(); comp.VerifyIL("Program.Test", @" diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenScriptTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenScriptTests.cs index cee3c4346e82d..27a58c250f995 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenScriptTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenScriptTests.cs @@ -554,7 +554,7 @@ public void SubmissionEntryPoint() "s0.dll", SyntaxFactory.ParseSyntaxTree(source0, options: TestOptions.Script), references); - var verifier = CompileAndVerify(s0, verify: Verification.Fails); + var verifier = CompileAndVerify(s0, verify: Verification.FailsPEVerify); var methodData = verifier.TestData.GetMethodData(""); Assert.Equal("System.Threading.Tasks.Task", ((MethodSymbol)methodData.Method).ReturnType.ToDisplayString()); methodData.VerifyIL( diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs index e2fedf4e12ac4..5a37f18a486d1 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs @@ -5233,7 +5233,8 @@ public RefLike M() public ref struct RefLike{} } "; - var verifier = CompileAndVerify(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), expectedOutput: @"--- + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + var verifier = CompileAndVerify(source, verify: Verification.FailsILVerify, options: TestOptions.DebugExe.WithAllowUnsafe(true), expectedOutput: @"--- M --- ---"); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs index 418c3a0778b2b..24ca4f31d8f1c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs @@ -488,10 +488,11 @@ static void Main() } } "; + // PEVerify: [ : C::Main][mdToken=0x6000002][offset 0x00000002][found Native Int][expected unmanaged pointer] Unexpected type on the stack. CompileAndVerify(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_3), options: TestOptions.UnsafeReleaseExe, - verify: Verification.Fails).VerifyIL("C.Main", + verify: Verification.FailsPEVerify).VerifyIL("C.Main", @"{ // Code size 8 (0x8) .maxstack 1 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStructsAndEnum.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStructsAndEnum.cs index ae686f82fbf74..de064bf35c7ba 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStructsAndEnum.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStructsAndEnum.cs @@ -259,7 +259,8 @@ static void Main(string[] args) } } "; - var compilation = CompileAndVerify(source, expectedOutput: @""); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of '[...]S1', Expected = address of '[...]S1' } + var compilation = CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: @""); compilation.VerifyIL("S1.Equals(object)", @" @@ -448,7 +449,8 @@ static void Main() } } "; - var compilation = CompileAndVerify(source, expectedOutput: @" + // ILVerify: Unexpected type on the stack. { Offset = 31, Found = readonly address of '[...]NS.N2.S`2', Expected = address of '[...]NS.N2.S`2' } + var compilation = CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: @" Abc 255 q"); @@ -2365,8 +2367,8 @@ static void Main(string[] args) } "; - - var compilation = CompileAndVerify(source, expectedOutput: "0"); + // ILVerify: Unexpected type on the stack. { Offset = 10, Found = readonly address of '[...]C1', Expected = address of '[...]C1' } + var compilation = CompileAndVerify(source, verify: Verification.FailsILVerify, expectedOutput: "0"); compilation.VerifyIL("Program.Main", @" diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs index fe49890a36633..e6b1ef80892f5 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs @@ -77,7 +77,8 @@ static void Main(object[] args) Console.WriteLine((((DoubleAndStruct)args[0]).y).x); } }"; - var result = CompileAndVerify(source, options: TestOptions.DebugDll); + // ILVerify: Unexpected type on the stack. { Offset = 59, Found = readonly address of '[...]DoubleAndStruct', Expected = address of '[...]DoubleAndStruct' } + var result = CompileAndVerify(source, verify: Verification.FailsILVerify, options: TestOptions.DebugDll); result.VerifyIL("Program.Main(object[])", @" @@ -164,7 +165,8 @@ static void Main(object[] args) Console.WriteLine(((((OuterStruct)args[0]).z).y).x); } }"; - var result = CompileAndVerify(source, options: TestOptions.DebugDll); + // ILVerify: Unexpected type on the stack. { Offset = 34, Found = readonly address of '[...]OuterStruct', Expected = address of '[...]OuterStruct' } + var result = CompileAndVerify(source, verify: Verification.FailsILVerify, options: TestOptions.DebugDll); result.VerifyIL("Program.Main(object[])", @" @@ -4359,7 +4361,7 @@ public static void M() Callee3(default(T), default(T)); } } -", verify: Verification.Fails, options: TestOptions.ReleaseExe); +", verify: Verification.FailsPEVerify, options: TestOptions.ReleaseExe); verifier.VerifyIL("Program.M()", @"{ // Code size 297 (0x129) @@ -4492,7 +4494,7 @@ public static void M() Callee3(); } } -", verify: Verification.Fails, options: TestOptions.ReleaseExe); +", verify: Verification.FailsPEVerify, options: TestOptions.ReleaseExe); verifier.VerifyIL("Program.M()", @"{ // Code size 34 (0x22) @@ -5259,6 +5261,12 @@ static void Test(in T r) } }"; + // PEVerify: + // [ : Program::GetElementRef[T]][mdToken=0x6000004][offset 0x00000009][found readonly address of ref ][expected address of ref ] Unexpected type on the stack. + // [ : Program::GetElementRef[T]][mdToken= 0x6000004][offset 0x00000017][found readonly address of ref ][expected address of ref ] Unexpected type on the stack. + // ILVerify: + // Unexpected type on the stack. { Offset = 9, Found = readonly address of 'T', Expected = address of 'T' } + // Unexpected type on the stack. { Offset = 23, Found = readonly address of 'T', Expected = address of 'T' } var compilation = CompileAndVerify(source, expectedOutput: @"hihi", verify: Verification.Fails); var expectedIL = @" @@ -10458,7 +10466,7 @@ static void Main() Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "Goo").WithArguments("Test.Goo()")); // NOTE: the resulting IL is unverifiable, but not an error for compat reasons - CompileAndVerify(comp, verify: Verification.Fails).VerifyIL("Test.Main", + CompileAndVerify(comp, verify: Verification.FailsPEVerify).VerifyIL("Test.Main", @" { // Code size 11 (0xb) @@ -12280,7 +12288,8 @@ public MyManagedStruct(int x) n.n.num = x; } }"; - var comp = CompileAndVerify(source, expectedOutput: @"42", parseOptions: TestOptions.Regular7_2, verify: Verification.Fails); + // PEVerify: Cannot change initonly field outside its .ctor. + var comp = CompileAndVerify(source, expectedOutput: @"42", parseOptions: TestOptions.Regular7_2, verify: Verification.FailsPEVerify); comp.VerifyIL("Program.Main", @" @@ -12433,7 +12442,8 @@ public override string ToString() return null; } }"; - var comp = CompileAndVerify(source, expectedOutput: @"-10", verify: Verification.Fails); + // PEVerify: Cannot change initonly field outside its .ctor. + var comp = CompileAndVerify(source, expectedOutput: @"-10", verify: Verification.FailsPEVerify); comp.VerifyIL("Program.Main", @" @@ -13322,7 +13332,6 @@ private void PrintArgList(ArgIterator args) } } } - } "; var compilation = CompileAndVerify( @@ -17216,7 +17225,7 @@ static async Task MethodAsync() System.Threading.Tasks.Task`1[System.Object] Success True -").VerifyDiagnostics(); +", verify: Verification.FailsILVerify).VerifyDiagnostics(); } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs index 5f384747cd4e3..9ede78295356c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs @@ -21,9 +21,8 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static TestResources.NetFX.ValueTuple; using static Roslyn.Test.Utilities.TestMetadata; -using System.Runtime.CompilerServices; +using static TestResources.NetFX.ValueTuple; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { @@ -28562,41 +28561,33 @@ static void verify(FieldSymbol field) [Fact] public void TupleWithElementNamedWithDefaultName() { - // Instrumenting test as part of investigating flakiness: https://github.com/dotnet/roslyn/issues/52658 - for (int i = 0; i < 1000; i++) - { - string source = @" + string source = @" class C { (int Item1, int Item2) M() => throw null; } "; - var comp = CreateCompilation(source); - var m = (MethodSymbol)comp.GetMember("C.M"); - var tuple = m.ReturnType; - Assert.Equal("(System.Int32 Item1, System.Int32 Item2)", tuple.ToTestDisplayString()); - Assert.IsType(tuple); - - var item1 = tuple.GetMember("Item1"); - // Instrumenting test as part of investigating flakiness: https://github.com/dotnet/roslyn/issues/52658 - RoslynDebug.AssertOrFailFast(0 == item1.TupleElementIndex); - - var item1Underlying = item1.TupleUnderlyingField; - Assert.IsType(item1Underlying); - Assert.Equal("System.Int32 (System.Int32 Item1, System.Int32 Item2).Item1", item1Underlying.ToTestDisplayString()); - // Instrumenting test as part of investigating flakiness: https://github.com/dotnet/roslyn/issues/52658 - RoslynDebug.AssertOrFailFast(0 == item1Underlying.TupleElementIndex); - Assert.Same(item1Underlying, item1Underlying.TupleUnderlyingField); - - var item2 = tuple.GetMember("Item2"); - // Instrumenting test as part of investigating flakiness: https://github.com/dotnet/roslyn/issues/52658 - RoslynDebug.AssertOrFailFast(1 == item2.TupleElementIndex); - var item2Underlying = item2.TupleUnderlyingField; - Assert.IsType(item2Underlying); - // Instrumenting test as part of investigating flakiness: https://github.com/dotnet/roslyn/issues/52658 - RoslynDebug.AssertOrFailFast(1 == item2Underlying.TupleElementIndex); - Assert.Same(item2Underlying, item2Underlying.TupleUnderlyingField); - } + var comp = CreateCompilation(source); + var m = (MethodSymbol)comp.GetMember("C.M"); + var tuple = m.ReturnType; + Assert.Equal("(System.Int32 Item1, System.Int32 Item2)", tuple.ToTestDisplayString()); + Assert.IsType(tuple); + + var item1 = tuple.GetMember("Item1"); + Assert.Equal(0, item1.TupleElementIndex); + + var item1Underlying = item1.TupleUnderlyingField; + Assert.IsType(item1Underlying); + Assert.Equal("System.Int32 (System.Int32 Item1, System.Int32 Item2).Item1", item1Underlying.ToTestDisplayString()); + Assert.Equal(0, item1Underlying.TupleElementIndex); + Assert.Same(item1Underlying, item1Underlying.TupleUnderlyingField); + + var item2 = tuple.GetMember("Item2"); + Assert.Equal(1, item2.TupleElementIndex); + var item2Underlying = item2.TupleUnderlyingField; + Assert.IsType(item2Underlying); + Assert.Equal(1, item2Underlying.TupleElementIndex); + Assert.Same(item2Underlying, item2Underlying.TupleUnderlyingField); } [Fact] @@ -28615,6 +28606,19 @@ class C tuple.ToTestDisplayString()); Assert.IsType(tuple); + var item1 = tuple.GetMember("Item1"); + Assert.Equal("System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item1", + item1.ToTestDisplayString()); + Assert.Equal(0, item1.TupleElementIndex); + + var item1Underlying = item1.TupleUnderlyingField; + Assert.Equal("System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item1", + item1Underlying.ToTestDisplayString()); + Assert.IsType(item1Underlying); + Assert.Equal(-1, item1Underlying.TupleElementIndex); // should be zero, tracked by https://github.com/dotnet/roslyn/issues/58499 + + Assert.Same(tuple, item1Underlying.ContainingType); + var item8 = tuple.GetMember("Item8"); Assert.Equal("System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item8", item8.ToTestDisplayString()); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/DestructorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/DestructorTests.cs index 97dafd8064f78..de3165b242819 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/DestructorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/DestructorTests.cs @@ -698,7 +698,7 @@ public class B : A Diagnostic(ErrorCode.WRN_FinalizeMethod, "Finalize")); // We produce unverifiable code here as per bug resolution (compat concerns, not common case). - CompileAndVerify(compilation, verify: Verification.Fails).VerifyIL("B.Finalize", + CompileAndVerify(compilation, verify: Verification.FailsPEVerify).VerifyIL("B.Finalize", @" { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/IndexAndRangeTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/IndexAndRangeTests.cs index 62f565161795d..668905cf2ed05 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/IndexAndRangeTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/IndexAndRangeTests.cs @@ -3582,5 +3582,210 @@ class C Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c").WithLocation(10, 5) ); } + + [Fact] + public void PatternIndexArrayAndAwait_01() + { + var src = @" +class C +{ + static async System.Threading.Tasks.Task M1(int[] arr) + { + arr[^1] = await System.Threading.Tasks.Task.FromResult(0); + } + + static async System.Threading.Tasks.Task Main() + { + var arr = new[] { 123 }; + System.Console.WriteLine(arr[0]); + await M1(arr); + System.Console.WriteLine(arr[0]); + } +} +"; + CompileAndVerifyWithIndexAndRange(src, expectedOutput: +@" +123 +0 +").VerifyDiagnostics(); + } + + [Fact] + public void PatternIndexArrayAndAwait_02() + { + var src = @" +class C +{ + static async System.Threading.Tasks.Task M1(int[] arr) + { + (arr[^1], arr[0]) = (123, await System.Threading.Tasks.Task.FromResult(124)); + } + + static async System.Threading.Tasks.Task Main() + { + var arr = new int[2]; + await M1(arr); + System.Console.WriteLine(arr[0]); + System.Console.WriteLine(arr[1]); + } +} +"; + CompileAndVerifyWithIndexAndRange(src, expectedOutput: +@" +124 +123 +").VerifyDiagnostics(); + } + + [Fact] + public void PatternIndexArrayAndAwait_03() + { + var src = @" +class C +{ + static async System.Threading.Tasks.Task M1((int x, int y)[] arr) + { + arr[^1].x = await System.Threading.Tasks.Task.FromResult(124); + } + + static async System.Threading.Tasks.Task Main() + { + var arr = new (int x, int y)[1]; + await M1(arr); + System.Console.WriteLine(arr[0].x); + } +} +"; + CompileAndVerifyWithIndexAndRange(src, expectedOutput: +@" +124 +").VerifyDiagnostics(); + } + + [Fact] + [WorkItem(58569, "https://github.com/dotnet/roslyn/issues/58569")] + public void PatternIndexArrayAndAwait_04() + { + var src = @" +class C +{ + static async System.Threading.Tasks.Task M1((int x, int y)[] arr) + { + (arr[^1].x, arr[0].y) = (123, await System.Threading.Tasks.Task.FromResult(124)); + } + + static async System.Threading.Tasks.Task Main() + { + var arr = new (int x, int y)[2]; + await M1(arr); + System.Console.WriteLine(arr[0].y); + System.Console.WriteLine(arr[1].x); + } +} +"; + CompileAndVerifyWithIndexAndRange(src, expectedOutput: +@" +124 +123 +").VerifyDiagnostics(); + } + + [Fact] + [WorkItem(58569, "https://github.com/dotnet/roslyn/issues/58569")] + public void PatternIndexArrayAndAwait_05() + { + var src = @" +class C +{ + static async System.Threading.Tasks.Task M1((int x, int y)[] arr) + { + arr[^1].x += await System.Threading.Tasks.Task.FromResult(124); + } + + static async System.Threading.Tasks.Task Main() + { + var arr = new (int x, int y)[] { (1, 2) }; + await M1(arr); + System.Console.WriteLine(arr[0].x); + } +} +"; + CompileAndVerifyWithIndexAndRange(src, expectedOutput: +@" +125 +").VerifyDiagnostics(); + } + + [Fact] + public void PatternIndexArrayAndAwait_06() + { + var src = @" +class C +{ + static async System.Threading.Tasks.Task M1(int[] arr) + { + arr[^1] += await System.Threading.Tasks.Task.FromResult(124); + } + + static async System.Threading.Tasks.Task Main() + { + var arr = new int[] { 1 }; + await M1(arr); + System.Console.WriteLine(arr[0]); + } +} +"; + CompileAndVerifyWithIndexAndRange(src, expectedOutput: +@" +125 +").VerifyDiagnostics(); + } + + [Fact] + public void PatternIndexArrayAndAwait_07() + { + var src = @" +class C +{ + static async System.Threading.Tasks.Task M1(int[][] arr) + { + arr[^1][0] += await System.Threading.Tasks.Task.FromResult(124); + } + + static async System.Threading.Tasks.Task Main() + { + var arr = new[] { new[] { 1 } }; + await M1(arr); + System.Console.WriteLine(arr[0][0]); + } +} +"; + CompileAndVerifyWithIndexAndRange(src, expectedOutput: +@" +125 +").VerifyDiagnostics(); + } + + [Fact] + public void PatternIndexArrayAndAwait_08() + { + var src = @" +class C +{ + static async System.Threading.Tasks.Task M1((int x, int y)[] arr) + { + (arr[1..][^1].x, arr[1..][0].y) = (123, await System.Threading.Tasks.Task.FromResult(124)); + } + + static async System.Threading.Tasks.Task Main() + { + var arr = new (int x, int y)[5]; + await M1(arr); + System.Console.WriteLine(""Done""); + } +} +"; + CompileAndVerifyWithIndexAndRange(src, expectedOutput: "Done").VerifyDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs index 8791b07a346fe..23a68895a0263 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs @@ -4106,8 +4106,10 @@ static void Main() source: new[] { Parse(text) }, references: new[] { AacorlibRef }); - - var verifier = CompileAndVerify(comp, verify: Verification.Fails); + // PEVerify: + // Error: Assembly name contains leading spaces or path or extension. + // Type load failed. + var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify); verifier.VerifyIL("Program.Main", @" { // Code size 223 (0xdf) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs index adf112f0795f9..01018e8121e39 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs @@ -5812,7 +5812,7 @@ void M(int* pi, void* pv, sbyte sb, byte b, short s, ushort us, int i, uint ui, } } "; - CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", @" + CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify).VerifyIL("C.M", @" { // Code size 79 (0x4f) .maxstack 1 @@ -5902,7 +5902,7 @@ void M(int* pi, void* pv, sbyte sb, byte b, short s, ushort us, int i, uint ui, } } "; - CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", @" + CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify).VerifyIL("C.M", @" { // Code size 79 (0x4f) .maxstack 1 @@ -6499,7 +6499,7 @@ static void Main() } } "; - CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "1234", verify: Verification.Fails).VerifyIL("C.Main", @" + CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: "1234", verify: Verification.FailsPEVerify).VerifyIL("C.Main", @" { // Code size 120 (0x78) .maxstack 5 @@ -9784,7 +9784,7 @@ public static implicit operator C(int* p) } } "; - CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("C.M", @" + CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify).VerifyIL("C.M", @" { // Code size 12 (0xc) .maxstack 1 @@ -10146,8 +10146,11 @@ No overflow from (S15*)0 + sizeof(S15) No overflow from (S15*)0 + sizeof(S16) No overflow from (S16*)0 + sizeof(S15)"; } - - CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.Fails); + // PEVerify: + // [ : C+<>c__DisplayClass0_0::
b__0][mdToken=0x6000005][offset 0x00000012][found Native Int][expected unmanaged pointer] Unexpected type on the stack. + // [ : C+<> c__DisplayClass0_0::< Main > b__1][mdToken= 0x6000006][offset 0x00000012][found Native Int][expected unmanaged pointer] Unexpected type on the stack. + // [ : C +<> c__DisplayClass0_0::< Main > b__2][mdToken = 0x6000007][offset 0x00000012][found Native Int][expected unmanaged pointer] Unexpected type on the stack. + CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify); } [Fact] @@ -10328,7 +10331,10 @@ public static void Main() } } "; - CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails).VerifyDiagnostics(); + // PEVerify: + // [ : ChannelServices::.cctor][mdToken=0x6000005][offset 0x0000000C][found unmanaged pointer][expected unmanaged pointer] Unexpected type on the stack. + // [ : ChannelServices::GetPrivateContextsPerfCounters][mdToken= 0x6000002][offset 0x00000002][found Native Int][expected unmanaged pointer] Unexpected type on the stack. + CompileAndVerify(text, options: TestOptions.UnsafeReleaseExe, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [WorkItem(545026, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545026")] @@ -10342,7 +10348,9 @@ class C unsafe int* p = (int*)2; } "; - CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyDiagnostics( + // PEVerify: + // [ : C::.ctor][mdToken=0x6000001][offset 0x0000000A][found Native Int][expected unmanaged pointer] Unexpected type on the stack. + CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify).VerifyDiagnostics( // (4,9): warning CS0414: The field 'C.x' is assigned but its value is never used // int x = 1; Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "x").WithArguments("C.x")); @@ -10359,7 +10367,9 @@ class C int x = 1; } "; - CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyDiagnostics( + // PEVerify: + // [ : C::.ctor][mdToken=0x6000001][offset 0x00000003][found Native Int][expected unmanaged pointer] Unexpected type on the stack. + CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify).VerifyDiagnostics( // (5,9): warning CS0414: The field 'C.x' is assigned but its value is never used // int x = 1; Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "x").WithArguments("C.x")); @@ -10844,7 +10854,7 @@ unsafe struct S1 "; - var verifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll.WithConcurrentBuild(false), verify: Verification.Fails); + var verifier = CompileAndVerify(text, options: TestOptions.UnsafeReleaseDll.WithConcurrentBuild(false), verify: Verification.FailsPEVerify); } [Fact, WorkItem(748530, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/748530")] @@ -11360,7 +11370,10 @@ public static unsafe int Test(params int*[] types) return types.Length; } }"; - var comp = CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, expectedOutput: "0", verify: Verification.Fails); + // PEVerify: + // [ : Program::Main][mdToken= 0x6000001][offset 0x00000001] Unmanaged pointers are not a verifiable type. + // [ : Program::Main][mdToken = 0x6000001][offset 0x00000001] Unable to resolve token. + var comp = CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, expectedOutput: "0", verify: Verification.FailsPEVerify); comp.VerifyIL("Program.Main", @" { // Code size 17 (0x11) diff --git a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs index 0683a48eedec3..8ef70a205e535 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs @@ -13,6 +13,7 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; +using System.Text; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Symbols; @@ -178,7 +179,6 @@ namespace N.; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("N.X.field", "null").WithLocation(4, 21)); } - // Check that EmitMetadataOnly works [Fact] public void EmitMetadataOnly() { @@ -246,6 +246,309 @@ public static void Main() } } + [Fact] + public void EmitMetadataOnly_XmlDocs_NoDocMode_Success() + { + CSharpCompilation comp = CreateCompilation(@" +namespace Goo.Bar +{ + /// This should be emitted + public class Test1 + { + public static void SayHello() + { + Console.WriteLine(""hello""); + } + } +} +", assemblyName: "test", parseOptions: CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.None)); + + EmitResult emitResult; + byte[] mdOnlyImage; + byte[] xmlDocBytes; + + using (var peStream = new MemoryStream()) + using (var xmlStream = new MemoryStream()) + { + emitResult = comp.Emit(peStream, xmlDocumentationStream: xmlStream, options: new EmitOptions(metadataOnly: true)); + mdOnlyImage = peStream.ToArray(); + xmlDocBytes = xmlStream.ToArray(); + } + + Assert.True(emitResult.Success); + emitResult.Diagnostics.Verify(); + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted"); + Assert.Equal( +@" + + + test + + + + +", + Encoding.UTF8.GetString(xmlDocBytes)); + } + + [Fact] + public void EmitMetadataOnly_XmlDocs_NoDocMode_SyntaxWarning() + { + CSharpCompilation comp = CreateCompilation(@" +namespace Goo.Bar +{ + /// This should still emit + public class Test1 + { + public static void SayHello() + { + Console.WriteLine(""hello""); + } + } +} +", assemblyName: "test", parseOptions: CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.None)); + + EmitResult emitResult; + byte[] mdOnlyImage; + byte[] xmlDocBytes; + + using (var peStream = new MemoryStream()) + using (var xmlStream = new MemoryStream()) + { + emitResult = comp.Emit(peStream, xmlDocumentationStream: xmlStream, options: new EmitOptions(metadataOnly: true)); + mdOnlyImage = peStream.ToArray(); + xmlDocBytes = xmlStream.ToArray(); + } + + Assert.True(emitResult.Success); + emitResult.Diagnostics.Verify(); + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted"); + Assert.Equal( + @" + + + test + + + + +", + Encoding.UTF8.GetString(xmlDocBytes)); + } + + [Fact] + public void EmitMetadataOnly_XmlDocs_DiagnoseDocMode_SyntaxWarning() + { + CSharpCompilation comp = CreateCompilation(@" +namespace Goo.Bar +{ + /// This should still emit + public class Test1 + { + public static void SayHello() + { + Console.WriteLine(""hello""); + } + } +} +", assemblyName: "test", parseOptions: CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.Diagnose)); + + EmitResult emitResult; + byte[] mdOnlyImage; + byte[] xmlDocBytes; + + using (var peStream = new MemoryStream()) + using (var xmlStream = new MemoryStream()) + { + emitResult = comp.Emit(peStream, xmlDocumentationStream: xmlStream, options: new EmitOptions(metadataOnly: true)); + mdOnlyImage = peStream.ToArray(); + xmlDocBytes = xmlStream.ToArray(); + } + + // This should not fail the emit (as it's a warning). + Assert.True(emitResult.Success); + emitResult.Diagnostics.Verify( + // (5,1): warning CS1570: XML comment has badly formed XML -- 'Expected an end tag for element 'summary'.' + // public class Test1 + Diagnostic(ErrorCode.WRN_XMLParseError, "").WithArguments("summary").WithLocation(5, 1), + // (7,28): warning CS1591: Missing XML comment for publicly visible type or member 'Test1.SayHello()' + // public static void SayHello() + Diagnostic(ErrorCode.WRN_MissingXMLComment, "SayHello").WithArguments("Goo.Bar.Test1.SayHello()").WithLocation(7, 28)); + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted"); + Assert.Equal( +@" + + + test + + + + + +", + Encoding.UTF8.GetString(xmlDocBytes)); + } + + [Fact] + public void EmitMetadataOnly_XmlDocs_DiagnoseDocMode_SemanticWarning() + { + CSharpCompilation comp = CreateCompilation(@" +namespace Goo.Bar +{ + /// + public class Test1 + { + public static void SayHello() + { + Console.WriteLine(""hello""); + } + } +} +", assemblyName: "test", parseOptions: CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.Diagnose)); + + EmitResult emitResult; + byte[] mdOnlyImage; + byte[] xmlDocBytes; + + using (var peStream = new MemoryStream()) + using (var xmlStream = new MemoryStream()) + { + emitResult = comp.Emit(peStream, xmlDocumentationStream: xmlStream, options: new EmitOptions(metadataOnly: true)); + mdOnlyImage = peStream.ToArray(); + xmlDocBytes = xmlStream.ToArray(); + } + + // This should not fail the emit (as it's a warning). + Assert.True(emitResult.Success); + emitResult.Diagnostics.Verify( + // (4,29): warning CS1574: XML comment has cref attribute 'T' that could not be resolved + // /// + Diagnostic(ErrorCode.WRN_BadXMLRef, "T").WithArguments("T").WithLocation(4, 29), + // (7,28): warning CS1591: Missing XML comment for publicly visible type or member 'Test1.SayHello()' + // public static void SayHello() + Diagnostic(ErrorCode.WRN_MissingXMLComment, "SayHello").WithArguments("Goo.Bar.Test1.SayHello()").WithLocation(7, 28)); + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted"); + Assert.Equal( +@" + + + test + + + + + + + +", + Encoding.UTF8.GetString(xmlDocBytes)); + } + + [Fact] + public void EmitMetadataOnly_XmlDocs_DiagnoseDocMode_Success() + { + CSharpCompilation comp = CreateCompilation(@" +namespace Goo.Bar +{ + /// This should emit + public class Test1 + { + public static void SayHello() + { + Console.WriteLine(""hello""); + } + } +} +", assemblyName: "test", parseOptions: CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.Diagnose)); + + EmitResult emitResult; + byte[] mdOnlyImage; + byte[] xmlDocBytes; + + using (var peStream = new MemoryStream()) + using (var xmlStream = new MemoryStream()) + { + emitResult = comp.Emit(peStream, xmlDocumentationStream: xmlStream, options: new EmitOptions(metadataOnly: true)); + mdOnlyImage = peStream.ToArray(); + xmlDocBytes = xmlStream.ToArray(); + } + + // This should not fail the emit (as it's a warning). + Assert.True(emitResult.Success); + emitResult.Diagnostics.Verify( + // (7,28): warning CS1591: Missing XML comment for publicly visible type or member 'Test1.SayHello()' + // public static void SayHello() + Diagnostic(ErrorCode.WRN_MissingXMLComment, "SayHello").WithArguments("Goo.Bar.Test1.SayHello()").WithLocation(7, 28)); + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted"); + Assert.Equal( +@" + + + test + + + + This should emit + + + +", + Encoding.UTF8.GetString(xmlDocBytes)); + } + + [Fact] + public void EmitMetadataOnly_XmlDocs_ParseDocMode_Success() + { + CSharpCompilation comp = CreateCompilation(@" +namespace Goo.Bar +{ + /// This should emit + public class Test1 + { + public static void SayHello() + { + Console.WriteLine(""hello""); + } + } +} +", assemblyName: "test", parseOptions: CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.Parse)); + + EmitResult emitResult; + byte[] mdOnlyImage; + byte[] xmlDocBytes; + + using (var peStream = new MemoryStream()) + using (var xmlStream = new MemoryStream()) + { + emitResult = comp.Emit(peStream, xmlDocumentationStream: xmlStream, options: new EmitOptions(metadataOnly: true)); + mdOnlyImage = peStream.ToArray(); + xmlDocBytes = xmlStream.ToArray(); + } + + Assert.True(emitResult.Success); + emitResult.Diagnostics.Verify(); + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted"); + Assert.Equal( + @" + + + test + + + + This should emit + + + +", + Encoding.UTF8.GetString(xmlDocBytes)); + } + [Fact] public void EmitRefAssembly_PrivateMain() { @@ -4724,6 +5027,8 @@ public void Bug769741() { var comp = CreateEmptyCompilation("", new[] { TestReferences.SymbolsTests.netModule.x64COFF }, options: TestOptions.DebugDll); // modules not supported in ref emit + // PEVerify: [HRESULT 0x8007000B] - An attempt was made to load a program with an incorrect format. + // ILVerify: Internal.IL.VerifierException : No system module specified CompileAndVerify(comp, verify: Verification.Fails); Assert.NotSame(comp.Assembly.CorLibrary, comp.Assembly); comp.GetSpecialType(SpecialType.System_Int32); @@ -5229,7 +5534,8 @@ public void CompileAndVerifyModuleIncludesAllModules() var modRef = CreateCompilation("public class A { }", options: TestOptions.ReleaseModule, assemblyName: "refMod").EmitToImageReference(); var comp = CreateCompilation("public class B : A { }", references: new[] { modRef }, assemblyName: "sourceMod"); - CompileAndVerify(comp, symbolValidator: module => + // ILVerify: Assembly or module not found: refMod + CompileAndVerify(comp, verify: Verification.FailsILVerify, symbolValidator: module => { var b = module.GlobalNamespace.GetTypeMember("B"); Assert.Equal("B", b.Name); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.cs index 068ba6382dc68..3bba6ef768d64 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.cs @@ -481,7 +481,8 @@ class C var compilation0 = CreateEmptyCompilation(src0, new[] { MscorlibRef, ref01, ref11 }, assemblyName: "C", options: TestOptions.DebugDll); var compilation1 = compilation0.WithSource(src1).WithReferences(new[] { MscorlibRef, ref02, ref12 }); - var v0 = CompileAndVerify(compilation0); + // ILVerify: Multiple modules named 'Lib' were found + var v0 = CompileAndVerify(compilation0, verify: Verification.FailsILVerify); var f0 = compilation0.GetMember("C.F"); var f1 = compilation1.GetMember("C.F"); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueDelegateCacheTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueDelegateCacheTests.cs new file mode 100644 index 0000000000000..3b50141864d50 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueDelegateCacheTests.cs @@ -0,0 +1,344 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.CodeGen; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.CSharp.UnitTests; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests; + +public class EditAndContinueDelegateCacheTests : EditAndContinueTestBase +{ + [Fact] + public void TargetChanged0() + { + var source0 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target0; +} +"; + var source1 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target1; +} +"; + var compilation0 = CreateCompilation(source0); + var compilation1 = compilation0.WithSource(source1); + + Assert.Equal(compilation0.LanguageVersion, compilation1.LanguageVersion); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var v0 = CompileAndVerify(compilation0); + using var moduleData0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var methodData0 = v0.TestData.GetMethodData("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(moduleData0, methodData0.EncDebugInfoProvider()); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + diff1.VerifyIL("C.F", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O#1.<0>__Target1"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int C.Target1()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.<>O#1.<0>__Target1"" + IL_001b: ret +} +"); + + var reader0 = moduleData0.MetadataReader; + var reader1 = diff1.GetMetadata().Reader; + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C", "<>O"); + CheckNames(new[] { reader0, reader1 }, reader1.GetTypeDefNames(), "<>O#1"); + } + + [Fact] + public void TargetChanged1() + { + var source0 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target0; +} +"; + var source1 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target1; +} +"; + var compilation0 = CreateCompilation(source0); + var compilation1 = compilation0.WithSource(source1); + + Assert.Equal(compilation0.LanguageVersion, compilation1.LanguageVersion); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var v0 = CompileAndVerify(compilation0); + using var moduleData0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var methodData0 = v0.TestData.GetMethodData("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(moduleData0, methodData0.EncDebugInfoProvider()); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + diff1.VerifyIL("C.F", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O#1.<0>__Target1"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int C.Target1()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.<>O#1.<0>__Target1"" + IL_001b: ret +} +"); + + var reader0 = moduleData0.MetadataReader; + var reader1 = diff1.GetMetadata().Reader; + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C`1", "<>O"); + CheckNames(new[] { reader0, reader1 }, reader1.GetTypeDefNames(), "<>O#1"); + } + + [Fact] + public void TargetChanged2() + { + var source0 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target0; +} +"; + var source1 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target1; +} +"; + var compilation0 = CreateCompilation(source0); + var compilation1 = compilation0.WithSource(source1); + + Assert.Equal(compilation0.LanguageVersion, compilation1.LanguageVersion); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var v0 = CompileAndVerify(compilation0); + using var moduleData0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var methodData0 = v0.TestData.GetMethodData("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(moduleData0, methodData0.EncDebugInfoProvider()); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + diff1.VerifyIL("C.F", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O#1.<0>__Target1"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int C.Target1()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.<>O#1.<0>__Target1"" + IL_001b: ret +} +"); + + var reader0 = moduleData0.MetadataReader; + var reader1 = diff1.GetMetadata().Reader; + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C`1", "<>O"); + CheckNames(new[] { reader0, reader1 }, reader1.GetTypeDefNames(), "<>O#1"); + } + + [Fact] + public void TargetChanged3() + { + var source0 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target0; +} +"; + var source1 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target1; +} +"; + var compilation0 = CreateCompilation(source0); + var compilation1 = compilation0.WithSource(source1); + + Assert.Equal(compilation0.LanguageVersion, compilation1.LanguageVersion); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var v0 = CompileAndVerify(compilation0); + using var moduleData0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var methodData0 = v0.TestData.GetMethodData("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(moduleData0, methodData0.EncDebugInfoProvider()); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + diff1.VerifyIL("C.F", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__2_0#1.<0>__Target1"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int C.Target1()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.O__2_0#1.<0>__Target1"" + IL_001b: ret +} +"); + + var reader0 = moduleData0.MetadataReader; + var reader1 = diff1.GetMetadata().Reader; + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C`1", "<>O"); + CheckNames(new[] { reader0, reader1 }, reader1.GetTypeDefNames(), "O__2_0#1`1"); + } + + [Fact] + public void TargetChanged4() + { + var source0 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target0; +} +"; + var source1 = @" +class C +{ + static int Target0() => 0; + static int Target1() => 1; + + System.Func F() => Target1; +} +"; + var compilation0 = CreateCompilation(source0); + var compilation1 = compilation0.WithSource(source1); + + Assert.Equal(compilation0.LanguageVersion, compilation1.LanguageVersion); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var v0 = CompileAndVerify(compilation0); + using var moduleData0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var methodData0 = v0.TestData.GetMethodData("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(moduleData0, methodData0.EncDebugInfoProvider()); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + diff1.VerifyIL("C.F", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__2_0#1.<0>__Target1"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int C.Target1()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.O__2_0#1.<0>__Target1"" + IL_001b: ret +} +"); + + var reader0 = moduleData0.MetadataReader; + var reader1 = diff1.GetMetadata().Reader; + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "C`1", "O__2_0`1"); + CheckNames(new[] { reader0, reader1 }, reader1.GetTypeDefNames(), "O__2_0#1`1"); + } + +} diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs index 60340749e9788..4db804c90174b 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs @@ -5107,7 +5107,7 @@ public async Task F() Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)); - var v0 = CompileAndVerify(compilation0, verify: Verification.Fails); + var v0 = CompileAndVerify(compilation0, verify: Verification.FailsPEVerify); var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); var f0 = compilation0.GetMember("C.F"); @@ -5166,7 +5166,7 @@ public async Task F() // older versions of mscorlib don't contain IteratorStateMachineAttribute Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); - var v0 = CompileAndVerify(compilation0, verify: Verification.Fails); + var v0 = CompileAndVerify(compilation0, verify: Verification.FailsPEVerify); v0.VerifyDiagnostics(); var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); @@ -5230,7 +5230,7 @@ public async Task F() Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); - var v0 = CompileAndVerify(compilation0, verify: Verification.Fails); + var v0 = CompileAndVerify(compilation0, verify: Verification.FailsPEVerify); v0.VerifyDiagnostics(); var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); @@ -5331,7 +5331,7 @@ public async Task F() Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); - var v0 = CompileAndVerify(compilation0, verify: Verification.Fails); + var v0 = CompileAndVerify(compilation0, verify: Verification.FailsPEVerify); var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); var f0 = compilation0.GetMember("C.F"); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.cs index db4b878a56567..0690435a76ff7 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.cs @@ -276,7 +276,8 @@ public static class EditAndContinueTestExtensions { internal static CSharpCompilation WithSource(this CSharpCompilation compilation, CSharpTestSource newSource) { - return compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(newSource.GetSyntaxTrees(TestOptions.Regular)); + var previousParseOptions = (CSharpParseOptions)compilation.SyntaxTrees.FirstOrDefault()?.Options; + return compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(newSource.GetSyntaxTrees(previousParseOptions)); } internal static CSharpCompilation WithSource(this CSharpCompilation compilation, SyntaxTree newTree) diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs index 6bb089c31cd58..cd7b7e55ad9f2 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs @@ -1185,7 +1185,7 @@ void F() } [Fact] - public void Lambda_SynthesizedDelegate() + public void Lambda_SynthesizedDelegate_01() { var source0 = MarkedSource(@" class C @@ -1273,6 +1273,409 @@ void F() "C.<>c: {<>9__0_0, <>9__0_1#1, <>9__0_2#1, b__0_0, b__0_1#1, b__0_2#1}"); } + [Fact] + public void Lambda_SynthesizedDelegate_02() + { + var source0 = MarkedSource( +@"class C +{ + static unsafe void F() + { + var x = (int* a, int b) => *a; + } +}"); + var source1 = MarkedSource( +@"class C +{ + static unsafe void F() + { + var x = (int* a, int b) => b; + var y = (int a, int* b) => a; + var z = (int* a) => a; + } +}"); + var source2 = MarkedSource( +@"class C +{ + static unsafe void F() + { + var x = (int* a, int b) => b; + var y = (int a, int* b) => *b; + var z = (int* a) => a; + } +}"); + var source3 = MarkedSource( +@"class C +{ + static unsafe void F() + { + var x = (int* a, int b) => b; + var y = (int a, int* b) => b; + var z = (int* a) => a; + } +}"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll.WithAllowUnsafe(true).WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation1 = compilation0.WithSource(source1.Tree); + var compilation2 = compilation1.WithSource(source2.Tree); + var compilation3 = compilation2.WithSource(source3.Tree); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var reader0 = md0.MetadataReader; + + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + var method2 = compilation2.GetMember("C.F"); + var method3 = compilation3.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "C", "<>c"); + CheckNames(reader0, reader0.GetMethodDefNames(), ".ctor", "Invoke", "F", ".ctor", ".cctor", ".ctor", "b__0_0"); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + var reader1 = md1.Reader; + var readers = new[] { reader0, reader1 }; + + EncValidation.VerifyModuleMvid(1, reader0, reader1); + + CheckNames(readers, reader1.GetTypeDefNames(), "<>f__AnonymousDelegate1", "<>f__AnonymousDelegate2"); + CheckNames(readers, reader1.GetMethodDefNames(), "F", "b__0_0", ".ctor", "Invoke", ".ctor", "Invoke", "b__0_1#1", "b__0_2#1"); + + diff1.VerifySynthesizedMembers( + "C: {<>c}", + "C.<>c: {<>9__0_0, <>9__0_1#1, <>9__0_2#1, b__0_0, b__0_1#1, b__0_2#1}"); + + var diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method1, method2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables: true))); + + using var md2 = diff2.GetMetadata(); + var reader2 = md2.Reader; + readers = new[] { reader0, reader1, reader2 }; + + EncValidation.VerifyModuleMvid(2, reader1, reader2); + + CheckNames(readers, reader2.GetTypeDefNames()); + CheckNames(readers, reader2.GetMethodDefNames(), "F", "b__0_0", "b__0_1#1", "b__0_2#1"); + + diff2.VerifySynthesizedMembers( + "C: {<>c}", + "C.<>c: {<>9__0_0, <>9__0_1#1, <>9__0_2#1, b__0_0, b__0_1#1, b__0_2#1}"); + + var diff3 = compilation3.EmitDifference( + diff2.NextGeneration, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method2, method3, GetSyntaxMapFromMarkers(source2, source3), preserveLocalVariables: true))); + + Assert.False(diff3.EmitResult.Success); + diff3.EmitResult.Diagnostics.Verify( + // error CS8984: Cannot update because an inferred delegate type has changed. + Diagnostic(ErrorCode.ERR_EncUpdateFailedDelegateTypeChanged).WithLocation(1, 1)); + } + + [Fact] + public void Lambda_SynthesizedDelegate_03() + { + var source0 = MarkedSource( +@"class A { } +struct B { } +class C +{ + static unsafe void F() + { + var x = (B* a, int b) => a; + } +}"); + var source1 = MarkedSource( +@"class A { } +struct B { } +class C +{ + static unsafe void F() + { + var x = (B* a, int b) => b; + } +}"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll.WithAllowUnsafe(true).WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var reader0 = md0.MetadataReader; + + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "<>f__AnonymousDelegate0", "A", "B`1", "C", "<>c"); + CheckNames(reader0, reader0.GetMethodDefNames(), ".ctor", "Invoke", ".ctor", "F", ".ctor", ".cctor", ".ctor", "b__0_0"); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + Assert.False(diff1.EmitResult.Success); + diff1.EmitResult.Diagnostics.Verify( + // error CS8984: Cannot update because an inferred delegate type has changed. + Diagnostic(ErrorCode.ERR_EncUpdateFailedDelegateTypeChanged).WithLocation(1, 1)); + } + + [Fact] + public void Lambda_SynthesizedDelegate_04() + { + var source0 = MarkedSource( +@"class A { } +struct B { } +class C +{ + static unsafe void F() + { + } +}"); + var source1 = MarkedSource( +@"class A { } +struct B { } +class C +{ + static unsafe void F() + { + var x = (B* a, int b) => a; + } +}"); + var source2 = MarkedSource( +@"class A { } +struct B { } +class C +{ + static unsafe void F() + { + var x = (B* a, int b) => b; + } +}"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll.WithAllowUnsafe(true).WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation1 = compilation0.WithSource(source1.Tree); + var compilation2 = compilation1.WithSource(source2.Tree); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var reader0 = md0.MetadataReader; + + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + var method2 = compilation2.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "A", "B`1", "C"); + CheckNames(reader0, reader0.GetMethodDefNames(), ".ctor", "F", ".ctor"); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + var reader1 = md1.Reader; + var readers = new[] { reader0, reader1 }; + + EncValidation.VerifyModuleMvid(1, reader0, reader1); + + CheckNames(readers, reader1.GetTypeDefNames(), "<>f__AnonymousDelegate0", "<>c"); + CheckNames(readers, reader1.GetMethodDefNames(), "F", ".ctor", "Invoke", ".cctor", ".ctor", "b__0#1"); + + diff1.VerifySynthesizedMembers( + "C.<>c: {<>9__0#1, b__0#1}", + "C: {<>c}"); + + var diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method1, method2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables: true))); + + Assert.False(diff2.EmitResult.Success); + diff2.EmitResult.Diagnostics.Verify( + // error CS8984: Cannot update because an inferred delegate type has changed. + Diagnostic(ErrorCode.ERR_EncUpdateFailedDelegateTypeChanged).WithLocation(1, 1)); + } + + [Fact] + public void Lambda_SynthesizedDelegate_05() + { + var source0 = MarkedSource( +@"class C where T : unmanaged +{ + static unsafe void F() where U : unmanaged + { + var x = (T t, U* u) => *u; + } +}"); + var source1 = MarkedSource( +@"class C where T : unmanaged +{ + static unsafe void F() where U : unmanaged + { + var x = (T t, U* u) => default(U); + var y = (U u, T* t) => *t; + } +}"); + var source2 = MarkedSource( +@"class C where T : unmanaged +{ + static unsafe void F() where U : unmanaged + { + var x = (T t, U* u) => *u; + var y = (U u, T* t) => *t; + } +}"); + var source3 = MarkedSource( +@"class C where T : unmanaged +{ + static unsafe void F() where U : unmanaged + { + var x = (T t, U* u) => *u; + var y = (U u, T* t) => t; + } +}"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll.WithAllowUnsafe(true).WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation1 = compilation0.WithSource(source1.Tree); + var compilation2 = compilation1.WithSource(source2.Tree); + var compilation3 = compilation2.WithSource(source3.Tree); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var reader0 = md0.MetadataReader; + + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + var method2 = compilation2.GetMember("C.F"); + var method3 = compilation3.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "<>f__AnonymousDelegate0`2", "EmbeddedAttribute", "IsUnmanagedAttribute", "C`1", "<>c__0`1"); + CheckNames(reader0, reader0.GetMethodDefNames(), ".ctor", "Invoke", ".ctor", ".ctor", "F", ".ctor", ".cctor", ".ctor", "b__0_0"); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + var reader1 = md1.Reader; + var readers = new[] { reader0, reader1 }; + + EncValidation.VerifyModuleMvid(1, reader0, reader1); + + CheckNames(readers, reader1.GetTypeDefNames(), "<>f__AnonymousDelegate1`2"); + CheckNames(readers, reader1.GetMethodDefNames(), "F", "b__0_0", ".ctor", "Invoke", "b__0_1#1"); + + diff1.VerifySynthesizedMembers( + "Microsoft.CodeAnalysis: {EmbeddedAttribute}", + "Microsoft: {CodeAnalysis}", + "System.Runtime: {CompilerServices}", + "C: {<>c__0}", + ": {Microsoft, System}", + "System: {Runtime}", + "System.Runtime.CompilerServices: {IsUnmanagedAttribute}", + "C.<>c__0: {<>9__0_0, <>9__0_1#1, b__0_0, b__0_1#1}"); + + var diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method1, method2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables: true))); + + using var md2 = diff2.GetMetadata(); + var reader2 = md2.Reader; + readers = new[] { reader0, reader1, reader2 }; + + EncValidation.VerifyModuleMvid(2, reader1, reader2); + + CheckNames(readers, reader2.GetTypeDefNames()); + CheckNames(readers, reader2.GetMethodDefNames(), "F", "b__0_0", "b__0_1#1"); + + diff2.VerifySynthesizedMembers( + "Microsoft.CodeAnalysis: {EmbeddedAttribute}", + "System: {Runtime}", + ": {Microsoft, System}", + "C: {<>c__0}", + "System.Runtime.CompilerServices: {IsUnmanagedAttribute}", + "System.Runtime: {CompilerServices}", + "Microsoft: {CodeAnalysis}", + "C.<>c__0: {<>9__0_0, <>9__0_1#1, b__0_0, b__0_1#1}"); + + var diff3 = compilation3.EmitDifference( + diff2.NextGeneration, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method2, method3, GetSyntaxMapFromMarkers(source2, source3), preserveLocalVariables: true))); + + Assert.False(diff3.EmitResult.Success); + diff3.EmitResult.Diagnostics.Verify( + // error CS8984: Cannot update because an inferred delegate type has changed. + Diagnostic(ErrorCode.ERR_EncUpdateFailedDelegateTypeChanged).WithLocation(1, 1)); + } + + [Fact] + public void Lambda_SynthesizedDeletage_06() + { + var source0 = MarkedSource( +@"class C +{ + void F() + { + var x = (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12, int p13, int p14, int p15, int p16, int p17) => 1; + } +}"); + var source1 = MarkedSource( +@"class C +{ + void F() + { + var x = (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12, int p13, int p14, int p15, int p16, int p17) => 1; + + System.Console.WriteLine(1); + } +}"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var reader0 = md0.MetadataReader; + + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + CheckNames(reader0, reader0.GetTypeDefNames(), "", "<>F`18", "C", "<>c"); + CheckNames(reader0, reader0.GetMethodDefNames(), ".ctor", "Invoke", "F", ".ctor", ".cctor", ".ctor", "b__0_0"); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + var reader1 = md1.Reader; + var readers = new[] { reader0, reader1 }; + + EncValidation.VerifyModuleMvid(1, reader0, reader1); + + CheckNames(readers, reader1.GetTypeDefNames()); + CheckNames(readers, reader1.GetMethodDefNames(), "F", "b__0_0"); + + diff1.VerifySynthesizedMembers( + "C.<>c: {<>9__0_0, b__0_0}", + "C: {<>c}"); + } + [WorkItem(962219, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/962219")] [Fact] public void PartialMethod() @@ -8857,7 +9260,7 @@ static void M2(object o) }"; var compilationPIA = CreateCompilation(sourcePIA, options: TestOptions.DebugDll); var referencePIA = compilationPIA.EmitToImageReference(embedInteropTypes: true); - var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, references: new MetadataReference[] { referencePIA, CSharpRef }); + var compilation0 = CreateCompilation(source0, parseOptions: TestOptions.Regular10, options: TestOptions.DebugDll, references: new MetadataReference[] { referencePIA, CSharpRef }); var compilation1A = compilation0.WithSource(source1A); var compilation1B = compilation0.WithSource(source1B); @@ -12493,7 +12896,8 @@ protected virtual bool PrintMembers(System.Text.StringBuilder builder) Row(4, TableIndex.TypeSpec, EditAndContinueOperation.Default), Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), // R.PrintMembers - Row(3, TableIndex.Param, EditAndContinueOperation.Default)); + Row(3, TableIndex.Param, EditAndContinueOperation.Default), + Row(21, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); CheckEncMap(reader1, Handle(20, TableIndex.TypeRef), @@ -12501,6 +12905,7 @@ protected virtual bool PrintMembers(System.Text.StringBuilder builder) Handle(22, TableIndex.TypeRef), Handle(10, TableIndex.MethodDef), Handle(3, TableIndex.Param), + Handle(21, TableIndex.CustomAttribute), Handle(3, TableIndex.StandAloneSig), Handle(4, TableIndex.TypeSpec), Handle(2, TableIndex.AssemblyRef)); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.cs index 88b332ce65632..44c719e3f2770 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.cs @@ -70,6 +70,7 @@ interface I { } for (int i = 0; i < 10; i++) { var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -128,6 +129,7 @@ struct S var compilation1 = compilation0.WithSource(source); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -161,6 +163,7 @@ static void M(I o) where T : I var compilation1 = compilation0.WithSource(source); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -196,6 +199,7 @@ .method public abstract virtual instance object modopt(A) [] F(int32 modopt(obje Assert.Equal(1, ((ArrayTypeSymbol)member1.ReturnType).ElementTypeWithAnnotations.CustomModifiers.Length); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -240,6 +244,7 @@ abstract class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -291,6 +296,7 @@ abstract class C var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll).WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -328,6 +334,7 @@ public void F(D a) {} var compilation1 = compilation0.WithSource(source).WithReferences(MscorlibRef, lib1.ToMetadataReference()); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -369,6 +376,7 @@ class D {} var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -407,6 +415,7 @@ class D {} var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -446,6 +455,7 @@ struct D {} var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -488,6 +498,7 @@ class D {} var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -536,7 +547,7 @@ static void F() var reader0 = peModule0.Module.MetadataReader; var decoder0 = new MetadataDecoder(peModule0); - var anonymousTypeMap0 = PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0); + PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0, out var anonymousTypeMap0, out _); Assert.Equal("<>f__AnonymousType0", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("A", isKey: false, ignoreCase: false)))].Name); Assert.Equal("<>f__AnonymousType1", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("B", isKey: false, ignoreCase: false)))].Name); Assert.Equal(2, anonymousTypeMap0.Count); @@ -559,7 +570,7 @@ static void F() Assert.Equal("x1", x1.Name); Assert.Equal("x2", x2.Name); - var matcher = new CSharpSymbolMatcher(anonymousTypeMap0, null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); + var matcher = new CSharpSymbolMatcher(anonymousTypeMap0, null, null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); var mappedX1 = (Cci.IFieldDefinition)matcher.MapDefinition(x1); var mappedX2 = (Cci.IFieldDefinition)matcher.MapDefinition(x2); @@ -605,7 +616,7 @@ static void F() var reader0 = peModule0.Module.MetadataReader; var decoder0 = new MetadataDecoder(peModule0); - var anonymousTypeMap0 = PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0); + PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0, out var anonymousTypeMap0, out _); Assert.Equal("<>f__AnonymousType0", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("A", isKey: false, ignoreCase: false)))].Name); Assert.Equal("<>f__AnonymousType1", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("X", isKey: false, ignoreCase: false)))].Name); Assert.Equal("<>f__AnonymousType2", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("Y", isKey: false, ignoreCase: false)))].Name); @@ -628,7 +639,7 @@ static void F() var x1 = fields.Where(f => f.Name == "x1").Single(); var x2 = fields.Where(f => f.Name == "x2").Single(); - var matcher = new CSharpSymbolMatcher(anonymousTypeMap0, null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); + var matcher = new CSharpSymbolMatcher(anonymousTypeMap0, null, null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); var mappedX1 = (Cci.IFieldDefinition)matcher.MapDefinition(x1); var mappedX2 = (Cci.IFieldDefinition)matcher.MapDefinition(x2); @@ -654,6 +665,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -685,6 +697,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -716,6 +729,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -747,6 +761,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -778,6 +793,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -809,6 +825,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -840,6 +857,7 @@ public struct Vector var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -871,6 +889,7 @@ public struct Vector var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -902,6 +921,7 @@ public class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -933,6 +953,7 @@ public class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -978,6 +999,7 @@ struct C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1033,6 +1055,7 @@ struct C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1095,7 +1118,7 @@ int I.this[int anotherIndex] Assert.Equal("anotherIndex", parameters[0].Name); var emitContext = new EmitContext(peAssemblyBuilder, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); - var matcher = new CSharpSymbolMatcher(null, null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); + var matcher = new CSharpSymbolMatcher(null, null, null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); var mappedProperty = (Cci.IPropertyDefinition)matcher.MapDefinition(property.GetCciAdapter()); @@ -1123,6 +1146,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1155,6 +1179,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1187,6 +1212,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1217,6 +1243,7 @@ class C var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1273,7 +1300,7 @@ static void M(string? x) var reader0 = peModule0.Module.MetadataReader; var decoder0 = new MetadataDecoder(peModule0); - var anonymousTypeMap0 = PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0); + PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0, out var anonymousTypeMap0, out _); Assert.Equal("<>f__AnonymousType0", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("A", isKey: false, ignoreCase: false)))].Name); Assert.Equal("<>f__AnonymousType1", anonymousTypeMap0[new AnonymousTypeKey(ImmutableArray.Create(new AnonymousTypeKeyField("B", isKey: false, ignoreCase: false)))].Name); Assert.Equal(2, anonymousTypeMap0.Count); @@ -1295,7 +1322,7 @@ static void M(string? x) var y1 = fields.Where(f => f.Name == "y1").Single(); var y2 = fields.Where(f => f.Name == "y2").Single(); - var matcher = new CSharpSymbolMatcher(anonymousTypeMap0, null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); + var matcher = new CSharpSymbolMatcher(anonymousTypeMap0, null, null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); var mappedY1 = (Cci.IFieldDefinition)matcher.MapDefinition(y1); var mappedY2 = (Cci.IFieldDefinition)matcher.MapDefinition(y2); @@ -1329,6 +1356,7 @@ event Action F { add { } remove { } } var compilation1 = compilation0.WithSource(source); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1385,6 +1413,7 @@ unsafe class C var compilation1 = compilation0.WithSource(source); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1426,6 +1455,7 @@ unsafe class C var compilation1 = compilation0.WithSource(source2); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1484,6 +1514,7 @@ static void verify(string source1, string source2) var compilation1 = compilation0.WithSource(source2); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1514,6 +1545,7 @@ public record R var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1543,6 +1575,7 @@ public record R var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1573,6 +1606,7 @@ public record R var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1601,6 +1635,7 @@ public record R(int X) var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1634,6 +1669,7 @@ public R(int X) var compilation1 = compilation0.WithSource(source1); var matcher = new CSharpSymbolMatcher( + null, null, null, compilation1.SourceAssembly, @@ -1652,7 +1688,7 @@ public R(int X) } [Fact] - public void SynthesizedDelegates() + public void SynthesizedDelegates_01() { var source0 = @" using System; @@ -1688,7 +1724,7 @@ static void F() var reader0 = peModule0.Module.MetadataReader; var decoder0 = new MetadataDecoder(peModule0); - var synthesizedDelegates0 = PEDeltaAssemblyBuilder.GetSynthesizedDelegateMapFromMetadata(reader0, decoder0); + var synthesizedDelegates0 = PEDeltaAssemblyBuilder.GetAnonymousDelegateMapFromMetadata(reader0, decoder0); Assert.Contains(new SynthesizedDelegateKey("<>F{00000004}`3"), synthesizedDelegates0); Assert.Contains(new SynthesizedDelegateKey("<>A{00000003}`2"), synthesizedDelegates0); Assert.Contains(new SynthesizedDelegateKey("<>A{00000000,00000001}`33"), synthesizedDelegates0); @@ -1714,7 +1750,7 @@ static void F() Assert.Equal("<>9__0_1", field2.Name); Assert.Equal("<>9__0_2", field3.Name); - var matcher = new CSharpSymbolMatcher(null, synthesizedDelegates0, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); + var matcher = new CSharpSymbolMatcher(null, synthesizedDelegates0, null, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); var mappedField1 = (Cci.IFieldDefinition)matcher.MapDefinition(field1); var mappedField2 = (Cci.IFieldDefinition)matcher.MapDefinition(field2); @@ -1724,5 +1760,56 @@ static void F() Assert.Equal("<>9__0_1", mappedField2.Name); Assert.Equal("<>9__0_2", mappedField3.Name); } + + [Fact] + public void SynthesizedDelegates_02() + { + var source0 = +@"unsafe class Program +{ + static void Main() + { + var d1 = (int* p) => *p; + } +}"; + var source1 = +@"unsafe class Program +{ + static void Main() + { + var d1 = (int* p) => 1; + } +}"; + + var compilation0 = CreateCompilation(source0, options: TestOptions.UnsafeDebugDll); + var compilation1 = CreateCompilation(source1, options: TestOptions.UnsafeDebugDll); + + var peRef0 = compilation0.EmitToImageReference(); + var peAssemblySymbol0 = (PEAssemblySymbol)CreateCompilation("", new[] { peRef0 }).GetReferencedAssemblySymbol(peRef0); + var peModule0 = (PEModuleSymbol)peAssemblySymbol0.Modules[0]; + + var reader0 = peModule0.Module.MetadataReader; + var decoder0 = new MetadataDecoder(peModule0); + + PEDeltaAssemblyBuilder.GetAnonymousTypeMapFromMetadata(reader0, decoder0, out _, out var anonymousDelegates0); + Assert.Equal("<>f__AnonymousDelegate0", anonymousDelegates0["<>f__AnonymousDelegate0"].Name); + Assert.Equal(1, anonymousDelegates0.Count); + + var testData = new CompilationTestData(); + compilation1.EmitToArray(testData: testData); + var peAssemblyBuilder = (PEAssemblyBuilder)testData.Module; + + var type = compilation1.GetMember("Program"); + var displayClass = peAssemblyBuilder.GetSynthesizedTypes(type).Single(); + Assert.Equal("<>c", displayClass.Name); + + var emitContext = new EmitContext(peAssemblyBuilder, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); + var field0 = displayClass.GetFields(emitContext).Single(f => f.Name == "<>9__0_0"); + Assert.Equal("<>f__AnonymousDelegate0", field0.GetType(emitContext).ToString()); + + var matcher = new CSharpSymbolMatcher(null, null, anonymousDelegates0, compilation1.SourceAssembly, emitContext, peAssemblySymbol0); + var field1 = (Cci.IFieldDefinition)matcher.MapDefinition(field0); + Assert.Equal("<>9__0_0", field1.Name); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitCustomModifiers.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitCustomModifiers.cs index 57b74980239f0..a005d98afe66b 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EmitCustomModifiers.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitCustomModifiers.cs @@ -705,7 +705,7 @@ static void Main() }"; var compilation = CreateCompilationWithILAndMscorlib40(source, ilSource, options: TestOptions.UnsafeReleaseExe); compilation.VerifyDiagnostics(); - CompileAndVerify(compilation, verify: Verification.Fails); + CompileAndVerify(compilation, verify: Verification.FailsPEVerify); } [Fact] @@ -739,7 +739,7 @@ static void Main() }"; var compilation = CreateCompilationWithILAndMscorlib40(source, ilSource, options: TestOptions.UnsafeReleaseExe); compilation.VerifyDiagnostics(); - CompileAndVerify(compilation, verify: Verification.Fails); + CompileAndVerify(compilation, verify: Verification.FailsPEVerify); } } } diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs index 3a559fcdc2531..aa1f4128b5f91 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs @@ -110,6 +110,8 @@ public static void Main() } } "; + // ILVerify null ref + // Tracked by https://github.com/dotnet/roslyn/issues/58652 var compilation2 = CompileAndVerify( source2, new[] { new CSharpCompilationReference(compilation1) }, @@ -142,6 +144,8 @@ public static void Main() } } "; + // ILVerify null ref + // Tracked by https://github.com/dotnet/roslyn/issues/58652 var compilation2 = CompileAndVerify( source2, new[] { new CSharpCompilationReference(compilation1) }, @@ -179,6 +183,8 @@ public static void Main() } "; + // ILVerify null ref + // Tracked by https://github.com/dotnet/roslyn/issues/58652 var compilation2 = CompileAndVerify( source2, new[] { new CSharpCompilationReference(compilation1) }, diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs index 9800cc0faa0d2..2e90f86ad4ce2 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs @@ -206,7 +206,7 @@ public class Test : Class2 { } "; - CompileAndVerifyWithMscorlib40(sources, new[] { TestReferences.SymbolsTests.MultiModule.Assembly }, assemblyValidator: (assembly) => + CompileAndVerifyWithMscorlib40(sources, new[] { TestReferences.SymbolsTests.MultiModule.Assembly }, verify: Verification.FailsILVerify, assemblyValidator: (assembly) => { var refs2 = assembly.Modules[0].ReferencedAssemblies.Select(r => r.Name); Assert.Equal(2, refs2.Count()); @@ -242,7 +242,8 @@ public class Test : Class1 } "; // modules not supported in ref emit - CompileAndVerify(source, new[] { netModule1, netModule2 }, assemblyValidator: (assembly) => + // ILVerify: Assembly or module not found: netModule1 + CompileAndVerify(source, new[] { netModule1, netModule2 }, verify: Verification.FailsILVerify, assemblyValidator: (assembly) => { Assert.Equal(3, assembly.Modules.Length); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/GeneratedNamesTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/GeneratedNamesTests.cs new file mode 100644 index 0000000000000..f9f2183894ea9 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit/Emit/GeneratedNamesTests.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Emit +{ + public class GeneratedNamesTests + { + [Theory] + [InlineData("<>A", true, 0, 0)] + [InlineData("<>A{00010000}`8", true, 0, 8)] + [InlineData("<>A{00010000}#2`8", true, 2, 8)] + [InlineData("<>A{00010000,00000000}`16", true, 0, 16)] + [InlineData("<>A{00010000,00000000}#4`16", true, 4, 16)] + [InlineData("<>A`5", true, 0, 5)] + [InlineData("<>A`18", true, 0, 18)] + [InlineData("<>F`1", false, 0, 0)] + [InlineData("<>F`6", false, 0, 5)] + [InlineData("<>F`19", false, 0, 18)] + [InlineData("<>F#3`19", false, 3, 18)] + public void TryParseSynthesizedDelegateName_Success(string name, bool returnsVoid, int generation, int parameterCount) + { + Assert.True(GeneratedNames.TryParseSynthesizedDelegateName(name, out var actualByRefs, out var actualReturnsVoid, out var actualGeneration, out var actualParameterCount)); + + Assert.Equal(returnsVoid, actualReturnsVoid); + Assert.Equal(generation, actualGeneration); + Assert.Equal(parameterCount, actualParameterCount); + + + // We need to strip arity in order to validate round-tripping + name = MetadataHelpers.InferTypeArityAndUnmangleMetadataName(name, out _); + Assert.Equal(name, GeneratedNames.MakeSynthesizedDelegateName(actualByRefs, actualReturnsVoid, actualGeneration)); + } + + [Theory] + [InlineData("<>D")] + [InlineData("<>A{")] + [InlineData("<>A00}")] + [InlineData("<>ABCDEF")] + [InlineData("<>A{Z}")] + [InlineData("<>A#F")] + [InlineData("<>A{}")] + [InlineData("<>A{,}")] + [InlineData("<>A#")] + [InlineData("<>A{0,}")] + [InlineData("<>A{,1}")] + public void TryParseSynthesizedDelegateName_Failure(string name) + { + Assert.False(GeneratedNames.TryParseSynthesizedDelegateName(name, out _, out _, out _, out _)); + } + } +} diff --git a/src/Compilers/CSharp/Test/Emit/Emit/NoPiaEmbedTypes.cs b/src/Compilers/CSharp/Test/Emit/Emit/NoPiaEmbedTypes.cs index 542afad36bf62..a9b901390c2ec 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/NoPiaEmbedTypes.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/NoPiaEmbedTypes.cs @@ -1779,9 +1779,9 @@ interface UsePia5 : ITest29 Assert.Equal(VarianceKind.None, t7.Variance); }; - CompileAndVerify(compilation1, symbolValidator: metadataValidator, verify: Verification.Fails); + CompileAndVerify(compilation1, symbolValidator: metadataValidator, verify: Verification.FailsPEVerify); - CompileAndVerify(compilation2, symbolValidator: metadataValidator, verify: Verification.Fails); + CompileAndVerify(compilation2, symbolValidator: metadataValidator, verify: Verification.FailsPEVerify); } [Fact] @@ -4708,11 +4708,11 @@ public void M1() var compilation3 = CreateCompilation(consumer, options: TestOptions.DebugExe, references: new MetadataReference[] { new CSharpCompilationReference(piaCompilation2) }); - CompileAndVerify(compilation3, verify: Verification.Fails); + CompileAndVerify(compilation3, verify: Verification.FailsPEVerify); var compilation4 = CreateCompilation(consumer, options: TestOptions.DebugExe, references: new MetadataReference[] { MetadataReference.CreateFromStream(piaCompilation2.EmitToStream()) }); - CompileAndVerify(compilation4, verify: Verification.Fails); + CompileAndVerify(compilation4, verify: Verification.FailsPEVerify); } [Fact] @@ -5185,11 +5185,11 @@ public void M1() var compilation3 = CreateCompilation(consumer, options: TestOptions.DebugExe, references: new MetadataReference[] { new CSharpCompilationReference(piaCompilation2) }); - CompileAndVerify(compilation3, verify: Verification.Fails); + CompileAndVerify(compilation3, verify: Verification.FailsPEVerify); var compilation4 = CreateCompilation(consumer, options: TestOptions.DebugExe, references: new MetadataReference[] { MetadataReference.CreateFromStream(piaCompilation2.EmitToStream()) }); - CompileAndVerify(compilation4, verify: Verification.Fails); + CompileAndVerify(compilation4, verify: Verification.FailsPEVerify); } [ConditionalFact(typeof(ClrOnly), Reason = ConditionalSkipReason.NoPiaNeedsDesktop)] diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs index fd168d2486b92..e7a3b0e0ddf60 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs @@ -22,8 +22,6 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class AssemblyAttributeTests : CSharpTestBase { - private readonly string _netModuleName = GetUniqueName() + ".netmodule"; - [Fact] public void VersionAttribute() { @@ -300,7 +298,9 @@ public void MismatchedSurrogateInAssemblyCultureAttribute() string s = @"[assembly: System.Reflection.AssemblyCultureAttribute(""\uD800"")]"; var comp = CreateCompilation(s, options: TestOptions.ReleaseDll); - CompileAndVerify(comp, verify: Verification.Fails, symbolValidator: m => + // PEVerify: + // Warning: Invalid locale string. + CompileAndVerify(comp, verify: Verification.FailsPEVerify, symbolValidator: m => { var utf8 = new System.Text.UTF8Encoding(false, false); Assert.Equal(utf8.GetString(utf8.GetBytes("\uD800")), m.ContainingAssembly.Identity.CultureName); @@ -543,7 +543,9 @@ void M(Test x) {} } ", options: TestOptions.ReleaseDll, references: new[] { hash_module }); + // ILVerify: Assembly or module not found: hash_module CompileAndVerify(compilation, + verify: Verification.FailsILVerify, manifestResources: hash_resources, validator: (peAssembly) => { @@ -572,7 +574,9 @@ void M(Test x) {} } ", options: TestOptions.ReleaseDll, references: new[] { hash_module }); + // ILVerify: Assembly or module not found: hash_module CompileAndVerify(compilation, + verify: Verification.FailsILVerify, manifestResources: hash_resources, validator: (peAssembly) => { @@ -602,6 +606,7 @@ void M(Test x) {} ", options: TestOptions.ReleaseDll, references: new[] { hash_module }); CompileAndVerify(compilation, + verify: Verification.FailsILVerify, manifestResources: hash_resources, validator: (peAssembly) => { @@ -631,6 +636,7 @@ void M(Test x) {} ", options: TestOptions.ReleaseDll, references: new[] { hash_module }); CompileAndVerify(compilation, + verify: Verification.FailsILVerify, manifestResources: hash_resources, validator: (peAssembly) => { @@ -761,6 +767,7 @@ void M(Test x) {} ", options: TestOptions.ReleaseDll, references: new[] { hash_module_Comp.EmitToImageReference() }); CompileAndVerify(compilation, + verify: Verification.FailsILVerify, validator: (peAssembly) => { var peReader = peAssembly.ManifestModule.GetMetadataReader(); diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_CallerInfoAttributes.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_CallerInfoAttributes.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Conditional.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Conditional.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Conditional.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Conditional.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Dynamic.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Dynamic.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Dynamic.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Dynamic.cs index ceb4255b1e26f..f77709947667b 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Dynamic.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Dynamic.cs @@ -1155,6 +1155,8 @@ static void Main() comp = CreateEmptyCompilation(source1, references: new[] { ref0, SystemCoreRef }); comp.VerifyDiagnostics(); // Make sure we emit without errors when System.Boolean is missing. + // PEVerify: Type load failed. + // ILVerify: Failed to load type 'System.String' from assembly ... CompileAndVerify(comp, verify: Verification.Fails); } @@ -1189,6 +1191,8 @@ static void Main() comp = CreateEmptyCompilation(source1, references: new[] { ref0, SystemCoreRef }); comp.VerifyDiagnostics(); // Make sure we emit without errors when System.Boolean is missing. + // PEVerify: Type load failed. + // ILVerify: Internal.TypeSystem.TypeSystemException+TypeLoadException : Failed to load type 'System.String' from assembly ... CompileAndVerify(comp, verify: Verification.Fails); } diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Embedded.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Embedded.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Embedded.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Embedded.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Experimental.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Experimental.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Experimental.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Experimental.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_IsByRefLike.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsByRefLike.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_IsByRefLike.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsByRefLike.cs index d020c19a854ae..6cf7d507d903d 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_IsByRefLike.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsByRefLike.cs @@ -957,7 +957,8 @@ public ref struct NotTypedReference { } }"; var compilation1 = CreateEmptyCompilation(source1, assemblyName: GetUniqueName()); - CompileAndVerify(compilation1, verify: Verification.Fails, symbolValidator: module => + // PEVerify: Type load failed. + CompileAndVerify(compilation1, verify: Verification.FailsPEVerify, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("System.TypedReference"); AssertReferencedIsByRefLike(type, hasObsolete: false); diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_IsUnmanaged.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsUnmanaged.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_IsUnmanaged.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsUnmanaged.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Locations.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Locations.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Locations.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Locations.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_MarshalAs.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_MarshalAs.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_MarshalAs.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_MarshalAs.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_NativeInteger.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NativeInteger.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_NativeInteger.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NativeInteger.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Nullable.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Nullable.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Nullable.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Nullable.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_NullableContext.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NullableContext.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_NullableContext.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NullableContext.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_NullablePublicOnly.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NullablePublicOnly.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_NullablePublicOnly.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NullablePublicOnly.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_ReadOnlyStruct.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_ReadOnlyStruct.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_ReadOnlyStruct.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_ReadOnlyStruct.cs index 159326acfd8e6..2a148fe1f4794 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_ReadOnlyStruct.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_ReadOnlyStruct.cs @@ -427,6 +427,8 @@ public class Test public readonly struct S1{} }"; + // PEVerify: The module was expected to contain an assembly manifest. + // ILVerify: The format of a DLL or executable being loaded is invalid CompileAndVerify(code, verify: Verification.Fails, references: new[] { reference }, options: TestOptions.ReleaseModule, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("Test").GetTypeMember("S1"); diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_RefReadOnly.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_RefReadOnly.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_RefReadOnly.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_RefReadOnly.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Security.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Security.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Security.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Security.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_StructLayout.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_StructLayout.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_StructLayout.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_StructLayout.cs index a064579a50c2e..b4f3391d0c35a 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_StructLayout.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_StructLayout.cs @@ -215,10 +215,10 @@ class Structs }; CompileAndVerify(verifiable, assemblyValidator: validator); - CompileAndVerify(unverifiable, assemblyValidator: validator, verify: Verification.Fails); + CompileAndVerify(unverifiable, assemblyValidator: validator, verify: Verification.FailsPEVerify); // CLR limitation on type size, not a RefEmit bug: - CompileAndVerify(unloadable, assemblyValidator: validator, verify: Verification.Fails); + CompileAndVerify(unloadable, assemblyValidator: validator, verify: Verification.FailsPEVerify); } [Fact] @@ -336,7 +336,7 @@ public class C : B } "; // type C can't be loaded - CompileAndVerify(source, verify: Verification.Fails); + CompileAndVerify(source, verify: Verification.FailsPEVerify); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Synthesized.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Synthesized.cs similarity index 81% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Synthesized.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Synthesized.cs index b99215174c3e9..3ff1c68ec763e 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Synthesized.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Synthesized.cs @@ -652,6 +652,318 @@ internal class C2<[Attr] T2> { } Assert.Equal(new[] { "Attr" }, GetAttributeNames(typeParam.GetAttributes())); } + [Fact] + [WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")] + public void RecordSynthesizedMembers() + { + string source = @" +record R +{ + public int MyProperty { get; } +} +"; + CompileAndVerify(source, symbolValidator: validate, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)); + + static void validate(ModuleSymbol module) + { + var record = module.GlobalNamespace.GetTypeMember("R"); + Assert.Equal(15, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute. + + var equalityContractGetter = record.GetMember("get_EqualityContract"); + validateCompilerGeneratedAttribute(equalityContractGetter); + + var toString = record.GetMember(WellKnownMemberNames.ObjectToString); + validateCompilerGeneratedAttribute(toString); + + var printMembers = record.GetMember(WellKnownMemberNames.PrintMembersMethodName); + validateCompilerGeneratedAttribute(printMembers); + + var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName); + validateCompilerGeneratedAttribute(op_Equality); + + var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName); + validateCompilerGeneratedAttribute(op_Inequality); + + var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode); + validateCompilerGeneratedAttribute(getHashCode); + + var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals); + Assert.Equal(2, equals.Length); + validateCompilerGeneratedAttribute(equals[0]); + validateCompilerGeneratedAttribute(equals[1]); + + var clone = record.GetMember(WellKnownMemberNames.CloneMethodName); + validateCompilerGeneratedAttribute(clone); + + var ctor = record.GetMembers(WellKnownMemberNames.InstanceConstructorName); + Assert.Equal(2, ctor.Length); + Assert.Equal("R..ctor(R original)", ctor[0].ToTestDisplayString()); + validateCompilerGeneratedAttribute(ctor[0]); + Assert.Equal("R..ctor()", ctor[1].ToTestDisplayString()); // parameterless constructor + Assert.Empty(ctor[1].GetAttributes()); // shouldn't have attribute. + + var equalityContract = record.GetMember("EqualityContract"); + Assert.Empty(equalityContract.GetAttributes()); + + var myProperty = record.GetMember("MyProperty"); + Assert.Empty(myProperty.GetAttributes()); + + var myPropertyGetter = record.GetMember("get_MyProperty"); + validateCompilerGeneratedAttribute(myPropertyGetter); + + var myPropertyBackingField = record.GetMember("k__BackingField"); + validateCompilerGeneratedAttribute(myPropertyBackingField); + } + + static void validateCompilerGeneratedAttribute(Symbol symbol) + { + var attributeNames = GetAttributeNames(symbol.GetAttributes()); + Assert.Contains("CompilerGeneratedAttribute", attributeNames); + } + } + + [Fact] + [WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")] + public void RecordStructSynthesizedMembers() + { + string source = @" +record struct R +{ + public int MyProperty { get; } +} +"; + CompileAndVerify(source, symbolValidator: validate, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)); + + static void validate(ModuleSymbol module) + { + var record = module.GlobalNamespace.GetTypeMember("R"); + Assert.Equal(11, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute. + + var toString = record.GetMember(WellKnownMemberNames.ObjectToString); + validateCompilerGeneratedAttribute(toString); + + var printMembers = record.GetMember(WellKnownMemberNames.PrintMembersMethodName); + validateCompilerGeneratedAttribute(printMembers); + + var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName); + validateCompilerGeneratedAttribute(op_Equality); + + var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName); + validateCompilerGeneratedAttribute(op_Inequality); + + var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode); + validateCompilerGeneratedAttribute(getHashCode); + + var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals); + Assert.Equal(2, equals.Length); + validateCompilerGeneratedAttribute(equals[0]); + validateCompilerGeneratedAttribute(equals[1]); + + var ctor = record.GetMember(WellKnownMemberNames.InstanceConstructorName); + Assert.Empty(ctor.GetAttributes()); + + var myProperty = record.GetMember("MyProperty"); + Assert.Empty(myProperty.GetAttributes()); + + var myPropertyGetter = record.GetMember("get_MyProperty"); + validateCompilerGeneratedAttribute(myPropertyGetter); + + var myPropertyBackingField = record.GetMember("k__BackingField"); + validateCompilerGeneratedAttribute(myPropertyBackingField); + } + + static void validateCompilerGeneratedAttribute(Symbol symbol) + { + var attributeNames = GetAttributeNames(symbol.GetAttributes()); + Assert.Contains("CompilerGeneratedAttribute", attributeNames); + } + } + + [Fact] + [WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")] + public void RecordSynthesizedMembers_2() + { + string source = @" +record R(int P1); + +namespace System.Runtime.CompilerServices +{ + public static class IsExternalInit { } +} +"; + // [ : R::set_P1] Cannot change initonly field outside its .ctor. + CompileAndVerify(source, + symbolValidator: validate, + options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All), + verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails); + + static void validate(ModuleSymbol module) + { + var record = module.GlobalNamespace.GetTypeMember("R"); + Assert.Equal(17, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute. + + var p1_backingField = record.GetMember("k__BackingField"); + validateCompilerGeneratedAttribute(p1_backingField); + + var equalityContractGetter = record.GetMember("get_EqualityContract"); + validateCompilerGeneratedAttribute(equalityContractGetter); + + var get_P1 = record.GetMember("get_P1"); + validateCompilerGeneratedAttribute(get_P1); + + var set_P1 = record.GetMember("set_P1"); + validateCompilerGeneratedAttribute(set_P1); + + var toString = record.GetMember(WellKnownMemberNames.ObjectToString); + validateCompilerGeneratedAttribute(toString); + + var printMembers = record.GetMember(WellKnownMemberNames.PrintMembersMethodName); + validateCompilerGeneratedAttribute(printMembers); + + var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName); + validateCompilerGeneratedAttribute(op_Equality); + + var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName); + validateCompilerGeneratedAttribute(op_Inequality); + + var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode); + validateCompilerGeneratedAttribute(getHashCode); + + var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals); + Assert.Equal(2, equals.Length); + validateCompilerGeneratedAttribute(equals[0]); + validateCompilerGeneratedAttribute(equals[1]); + + var clone = record.GetMember(WellKnownMemberNames.CloneMethodName); + validateCompilerGeneratedAttribute(clone); + + var ctor = record.GetMembers(WellKnownMemberNames.InstanceConstructorName); + Assert.Equal(2, ctor.Length); + Assert.Equal("R..ctor(System.Int32 P1)", ctor[0].ToTestDisplayString()); + Assert.Equal("R..ctor(R original)", ctor[1].ToTestDisplayString()); + validateCompilerGeneratedAttribute(ctor[1]); + Assert.Empty(ctor[0].GetAttributes()); + + var deconstruct = record.GetMember(WellKnownMemberNames.DeconstructMethodName); + validateCompilerGeneratedAttribute(deconstruct); + + var equalityContract = record.GetMember("EqualityContract"); + Assert.Empty(equalityContract.GetAttributes()); + + var p1 = record.GetMember("P1"); + Assert.Empty(p1.GetAttributes()); + } + + static void validateCompilerGeneratedAttribute(Symbol symbol) + { + var attributeNames = GetAttributeNames(symbol.GetAttributes()); + Assert.Contains("CompilerGeneratedAttribute", attributeNames); + } + } + + [Fact] + [WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")] + public void RecordStructSynthesizedMembers_2() + { + string source = @" +record struct R(int P1); +"; + CompileAndVerify(source, symbolValidator: validate, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)); + + void validate(ModuleSymbol module) + { + var record = module.GlobalNamespace.GetTypeMember("R"); + Assert.Equal(14, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute. + + var p1_backingField = record.GetMember("k__BackingField"); + validateCompilerGeneratedAttribute(p1_backingField); + + var ctor = record.GetMembers(WellKnownMemberNames.InstanceConstructorName); + Assert.Equal(2, ctor.Length); + Assert.Equal("R..ctor()", ctor[0].ToTestDisplayString()); + Assert.Equal("R..ctor(System.Int32 P1)", ctor[1].ToTestDisplayString()); + Assert.Empty(ctor[0].GetAttributes()); + Assert.Empty(ctor[1].GetAttributes()); + + var get_P1 = record.GetMember("get_P1"); + validateCompilerGeneratedAttribute(get_P1); + + var set_P1 = record.GetMember("set_P1"); + validateCompilerGeneratedAttribute(set_P1); + + var toString = record.GetMember(WellKnownMemberNames.ObjectToString); + validateCompilerGeneratedAttribute(toString); + + var printMembers = record.GetMember(WellKnownMemberNames.PrintMembersMethodName); + validateCompilerGeneratedAttribute(printMembers); + + var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName); + validateCompilerGeneratedAttribute(op_Equality); + + var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName); + validateCompilerGeneratedAttribute(op_Inequality); + + var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode); + validateCompilerGeneratedAttribute(getHashCode); + + var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals); + Assert.Equal(2, equals.Length); + validateCompilerGeneratedAttribute(equals[0]); + validateCompilerGeneratedAttribute(equals[1]); + + var deconstruct = record.GetMember(WellKnownMemberNames.DeconstructMethodName); + validateCompilerGeneratedAttribute(deconstruct); + + var p1 = record.GetMember("P1"); + Assert.Empty(p1.GetAttributes()); + } + + void validateCompilerGeneratedAttribute(Symbol symbol) + { + var attributeNames = GetAttributeNames(symbol.GetAttributes()); + Assert.Contains("CompilerGeneratedAttribute", attributeNames); + } + } + + [Fact] + [WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")] + public void AttributeIsMissing() + { + string source = @" +record struct R; +"; + var comp = CreateCompilation(source); + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_CompilerGeneratedAttribute); + var verifier = CompileAndVerify(comp, symbolValidator: validate); + verifier.VerifyDiagnostics(); + + void validate(ModuleSymbol module) + { + var record = module.GlobalNamespace.GetTypeMember("R"); + Assert.Equal(7, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute. + + var ctor = record.GetMember(WellKnownMemberNames.InstanceConstructorName); + Assert.Empty(ctor.GetAttributes()); + + var toString = record.GetMember(WellKnownMemberNames.ObjectToString); + Assert.Empty(toString.GetAttributes()); + + var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName); + Assert.Empty(op_Equality.GetAttributes()); + + var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName); + Assert.Empty(op_Inequality.GetAttributes()); + + var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode); + Assert.Empty(getHashCode.GetAttributes()); + + var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals); + Assert.Equal(2, equals.Length); + Assert.Empty(equals[0].GetAttributes()); + Assert.Empty(equals[1].GetAttributes()); + } + } + #endregion #region CompilationRelaxationsAttribute, RuntimeCompatibilityAttribute, DebuggableAttribute @@ -954,7 +1266,13 @@ public void MissingWellKnownAttributesNoDiagnosticsAndNoSynthesizedAttributes(Ou } else { - CompileAndVerify(compilation, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module => + // ILVerify: Failed to load type 'System.String' from assembly + // ILVerify: The format of a DLL or executable being loaded is invalid + var verify = outputKind.IsNetModule() + ? Verification.Fails + : Verification.FailsILVerify; + + CompileAndVerify(compilation, verify: verify, symbolValidator: module => { var assemblyAttributes = module.ContainingAssembly.GetAttributes(); Assert.Equal(0, assemblyAttributes.Length); diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Tuples.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Tuples.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Tuples.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Tuples.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs index b472499f4a267..8715f52c9b56d 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs @@ -3606,7 +3606,7 @@ public static int Main () // the resulting code does not need to verify // This is consistent with Dev10 behavior - CompileAndVerify(source, options: TestOptions.ReleaseDll, verify: Verification.Fails, sourceSymbolValidator: sourceValidator, symbolValidator: metadataValidator); + CompileAndVerify(source, options: TestOptions.ReleaseDll, verify: Verification.FailsPEVerify, sourceSymbolValidator: sourceValidator, symbolValidator: metadataValidator); } [Fact, WorkItem(544507, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544507")] @@ -5553,7 +5553,7 @@ public static void Main() {} // Dev10 Runtime Exception: // Unhandled Exception: System.TypeLoadException: Windows Runtime types can only be declared in Windows Runtime assemblies. - var verifier = CompileAndVerify(source, sourceSymbolValidator: sourceValidator, symbolValidator: metadataValidator, verify: Verification.Fails, targetFramework: TargetFramework.Mscorlib40); + var verifier = CompileAndVerify(source, sourceSymbolValidator: sourceValidator, symbolValidator: metadataValidator, verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Mscorlib40); } #endregion @@ -13718,5 +13718,77 @@ public void M() Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "this[..]").WithArguments("C.this[System.Range].get", "error").WithLocation(27, 13) ); } + + [Fact] + [WorkItem(59003, "https://github.com/dotnet/roslyn/issues/59003")] + public void ErrorInPropertyValue_01() + { + var source = @" +class C +{ + public int Count + { + [System.Runtime.CompilerServices.MethodImpl(MethodCodeType = System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + get; + private set; + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,53): error CS0599: Invalid value for named attribute argument 'MethodCodeType' + // [System.Runtime.CompilerServices.MethodImpl(MethodCodeType = System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "MethodCodeType = System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining").WithArguments("MethodCodeType").WithLocation(6, 53), + // (6,70): error CS0266: Cannot implicitly convert type 'System.Runtime.CompilerServices.MethodImplOptions' to 'System.Runtime.CompilerServices.MethodCodeType'. An explicit conversion exists (are you missing a cast?) + // [System.Runtime.CompilerServices.MethodImpl(MethodCodeType = System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining").WithArguments("System.Runtime.CompilerServices.MethodImplOptions", "System.Runtime.CompilerServices.MethodCodeType").WithLocation(6, 70) + ); + } + + [Fact] + [WorkItem(59003, "https://github.com/dotnet/roslyn/issues/59003")] + public void ErrorInPropertyValue_02() + { + var source = @" +class C +{ + public int Count + { + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized, MethodCodeType = (System.Runtime.CompilerServices.MethodCodeType)System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + get; + private set; + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,117): error CS0599: Invalid value for named attribute argument 'MethodCodeType' + // [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized, MethodCodeType = (System.Runtime.CompilerServices.MethodCodeType)System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "MethodCodeType = (System.Runtime.CompilerServices.MethodCodeType)System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining").WithArguments("MethodCodeType").WithLocation(6, 117) + ); + } + + [Fact] + public void ErrorInPropertyValue_03() + { + var source = @" +using System.Runtime.InteropServices; + +[StructLayout(CharSet=0)] +public struct S1 { } + +[StructLayout(LayoutKind.Sequential, CharSet=0)] +public struct S2 { } +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (4,2): error CS1729: 'StructLayoutAttribute' does not contain a constructor that takes 0 arguments + // [StructLayout(CharSet=0)] + Diagnostic(ErrorCode.ERR_BadCtorArgCount, "StructLayout(CharSet=0)").WithArguments("System.Runtime.InteropServices.StructLayoutAttribute", "0").WithLocation(4, 2), + // (7,38): error CS0599: Invalid value for named attribute argument 'CharSet' + // [StructLayout(LayoutKind.Sequential, CharSet=0)] + Diagnostic(ErrorCode.ERR_InvalidNamedArgument, "CharSet=0").WithArguments("CharSet").WithLocation(7, 38) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/EmitTestStrongNameProvider.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/EmitTestStrongNameProvider.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/EmitTestStrongNameProvider.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/EmitTestStrongNameProvider.cs diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/InternalsVisibleToAndStrongNameTests.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/InternalsVisibleToAndStrongNameTests.cs similarity index 98% rename from src/Compilers/CSharp/Test/Emit/Attributes/InternalsVisibleToAndStrongNameTests.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/InternalsVisibleToAndStrongNameTests.cs index ba775a35557ac..96a08399ae52c 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/InternalsVisibleToAndStrongNameTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/InternalsVisibleToAndStrongNameTests.cs @@ -3169,5 +3169,35 @@ internal class PublicKeyConstants comp2 = CreateCompilation(source2, new[] { imageReference }, assemblyName: "Issue57742_04"); comp2.VerifyDiagnostics(expected2); } + + [Fact] + [WorkItem(57742, "https://github.com/dotnet/roslyn/issues/57742")] + public void Issue57742_05() + { + string lib_cs = @" +using System.Runtime.CompilerServices; + +[ assembly: InternalsVisibleTo(""Issue57742_05, PublicKey=00240000048000009400000006020000002400005253413100040000010001002b986f6b5ea5717d35c72d38561f413e267029efa9b5f107b9331d83df657381325b3a67b75812f63a9436ceccb49494de8f574f8e639d4d26c0fcf8b0e9a1a196b80b6f6ed053628d10d027e032df2ed1d60835e5f47d32c9ef6da10d0366a319573362c821b5f8fa5abc5bb22241de6f666a85d82d6ba8c3090d01636bd2bb"") ] +internal class C {} +"; + var lib = CreateCompilation(lib_cs, assemblyName: "Issue57742_05_Lib"); + + string source1 = @" +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(C))] +"; + + var comp = CreateCompilation(source1, new[] { lib.ToMetadataReference() }, assemblyName: "Issue57742_05"); + var expected = new[] + { + // (2,67): error CS0281: Friend access was granted by 'Issue57742_05_Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null', but the public key of the output assembly ('') does not match that specified by the InternalsVisibleTo attribute in the granting assembly. + // [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(C))] + Diagnostic(ErrorCode.ERR_FriendRefNotEqualToThis, "C").WithArguments("Issue57742_05_Lib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "").WithLocation(2, 67) + }; + + comp.VerifyDiagnostics(expected); + + comp = CreateCompilation(source1, new[] { lib.EmitToImageReference() }, assemblyName: "Issue57742_05"); + comp.VerifyDiagnostics(expected); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/WellKnownAttributesTestBase.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/WellKnownAttributesTestBase.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Attributes/WellKnownAttributesTestBase.cs rename to src/Compilers/CSharp/Test/Emit2/Attributes/WellKnownAttributesTestBase.cs diff --git a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs new file mode 100644 index 0000000000000..74c56ba932660 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenMethodGroupConversionCachingTests.cs @@ -0,0 +1,6379 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen; + +public class CodeGenMethodGroupConversionCachingTests : CSharpTestBase +{ + const string PASS = "PASS"; + + [Fact] + public void Not_DelegateCreations_Static() + { + var source = @" +using System; +delegate void D(); +class C +{ + public static void Main(string[] args) + { + Invoke(new D(Target), new D(Target)); + } + + static void Target() { Console.WriteLine(""FAIL""); } + static void Invoke(D x, D y) { Console.Write(Object.ReferenceEquals(x, y) ? ""FAIL"" : ""PASS""); } +}"; + var verifier = CompileAndVerify(source, expectedOutput: PASS, symbolValidator: VerifyNoCacheContainersIn("C")); + verifier.VerifyIL("C.Main", @" +{ + // Code size 30 (0x1e) + .maxstack 3 + IL_0000: ldnull + IL_0001: ldftn ""void C.Target()"" + IL_0007: newobj ""D..ctor(object, System.IntPtr)"" + IL_000c: ldnull + IL_000d: ldftn ""void C.Target()"" + IL_0013: newobj ""D..ctor(object, System.IntPtr)"" + IL_0018: call ""void C.Invoke(D, D)"" + IL_001d: ret +} +"); + } + + [Fact] + public void Not_DelegateCreations_Instance() + { + var source = @" +using System; +delegate void D(); +class C +{ + public static void Main(string[] args) + { + var c = new C(); + c.Invoke(new D(c.Target), new D(c.Target)); + } + + void Target() { Console.WriteLine(""FAIL""); } + void Invoke(D x, D y) { Console.Write(Object.ReferenceEquals(x, y) ? ""FAIL"" : ""PASS""); } +}"; + var verifier = CompileAndVerify(source, expectedOutput: PASS, symbolValidator: VerifyNoCacheContainersIn("C")); + verifier.VerifyIL("C.Main", @" +{ + // Code size 37 (0x25) + .maxstack 4 + .locals init (C V_0) //c + IL_0000: newobj ""C..ctor()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: ldloc.0 + IL_0008: ldftn ""void C.Target()"" + IL_000e: newobj ""D..ctor(object, System.IntPtr)"" + IL_0013: ldloc.0 + IL_0014: ldftn ""void C.Target()"" + IL_001a: newobj ""D..ctor(object, System.IntPtr)"" + IL_001f: callvirt ""void C.Invoke(D, D)"" + IL_0024: ret +} +"); + } + + [Fact] + public void Not_Conversions_Instance() + { + var source = @" +using System; +delegate void D(); +class C +{ + public static void Main(string[] args) + { + var c = new C(); + c.Invoke(c.Target, c.Target); + } + + void Target() { Console.WriteLine(""FAIL""); } + void Invoke(D x, D y) { Console.Write(Object.ReferenceEquals(x, y) ? ""FAIL"" : ""PASS""); } +}"; + var verifier = CompileAndVerify(source, expectedOutput: PASS, symbolValidator: VerifyNoCacheContainersIn("C")); + verifier.VerifyIL("C.Main", @" +{ + // Code size 37 (0x25) + .maxstack 4 + .locals init (C V_0) //c + IL_0000: newobj ""C..ctor()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: ldloc.0 + IL_0008: ldftn ""void C.Target()"" + IL_000e: newobj ""D..ctor(object, System.IntPtr)"" + IL_0013: ldloc.0 + IL_0014: ldftn ""void C.Target()"" + IL_001a: newobj ""D..ctor(object, System.IntPtr)"" + IL_001f: callvirt ""void C.Invoke(D, D)"" + IL_0024: ret +} +"); + } + + [Fact] + public void Not_DelegateCreations_InstanceExtensionMethod() + { + var source = @" +using System; +delegate void D(); +class C +{ + public static void Main(string[] args) + { + var c = new C(); + c.Invoke(new D(c.Target), new D(c.Target)); + } + + void Invoke(D x, D y) { Console.Write(Object.ReferenceEquals(x, y) ? ""FAIL"" : ""PASS""); } +} +static class E +{ + public static void Target(this C that) { Console.WriteLine(""FAIL""); } +} +"; + // ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 14 } + var verifier = CompileAndVerify(source, expectedOutput: PASS, symbolValidator: VerifyNoCacheContainersIn("C"), verify: Verification.FailsILVerify); + verifier.VerifyIL("C.Main", @" +{ + // Code size 37 (0x25) + .maxstack 4 + .locals init (C V_0) //c + IL_0000: newobj ""C..ctor()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: ldloc.0 + IL_0008: ldftn ""void E.Target(C)"" + IL_000e: newobj ""D..ctor(object, System.IntPtr)"" + IL_0013: ldloc.0 + IL_0014: ldftn ""void E.Target(C)"" + IL_001a: newobj ""D..ctor(object, System.IntPtr)"" + IL_001f: callvirt ""void C.Invoke(D, D)"" + IL_0024: ret +} +"); + } + + [Fact] + public void Not_Conversions_InstanceExtensionMethod() + { + var source = @" +using System; +delegate void D(); +class C +{ + public static void Main(string[] args) + { + var c = new C(); + c.Invoke(c.Target, c.Target); + } + + void Invoke(D x, D y) { Console.Write(Object.ReferenceEquals(x, y) ? ""FAIL"" : ""PASS""); } +} +static class E +{ + public static void Target(this C that) { Console.WriteLine(""FAIL""); } +} +"; + // ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 14 } + var verifier = CompileAndVerify(source, expectedOutput: PASS, symbolValidator: VerifyNoCacheContainersIn("C"), verify: Verification.FailsILVerify); + verifier.VerifyIL("C.Main", @" +{ + // Code size 37 (0x25) + .maxstack 4 + .locals init (C V_0) //c + IL_0000: newobj ""C..ctor()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: ldloc.0 + IL_0008: ldftn ""void E.Target(C)"" + IL_000e: newobj ""D..ctor(object, System.IntPtr)"" + IL_0013: ldloc.0 + IL_0014: ldftn ""void E.Target(C)"" + IL_001a: newobj ""D..ctor(object, System.IntPtr)"" + IL_001f: callvirt ""void C.Invoke(D, D)"" + IL_0024: ret +} +"); + } + + [Fact] + public void Not_DelegateCreations_StaticExtensionMethod() + { + var source = @" +using System; +delegate void D(C arg); +class C +{ + public static void Main(string[] args) + { + var c = new C(); + c.Invoke(new D(E.Target), new D(E.Target)); + } + + void Invoke(D x, D y) { Console.Write(Object.ReferenceEquals(x, y) ? ""FAIL"" : ""PASS""); } +} +static class E +{ + public static void Target(this C that) { Console.WriteLine(""FAIL""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS, symbolValidator: VerifyNoCacheContainersIn("C")); + verifier.VerifyIL("C.Main", @" +{ + // Code size 35 (0x23) + .maxstack 4 + IL_0000: newobj ""C..ctor()"" + IL_0005: ldnull + IL_0006: ldftn ""void E.Target(C)"" + IL_000c: newobj ""D..ctor(object, System.IntPtr)"" + IL_0011: ldnull + IL_0012: ldftn ""void E.Target(C)"" + IL_0018: newobj ""D..ctor(object, System.IntPtr)"" + IL_001d: callvirt ""void C.Invoke(D, D)"" + IL_0022: ret +} +"); + } + + [Fact] + public void Not_InExpressionLamba0() + { + var source = @" +using System; +using System.Linq.Expressions; +class C +{ + public static void Main(string[] args) + { + Expression>> e = x => Target; + Console.WriteLine(e); + } + + static int Target(int x) => 0; +} +"; + var verifier = CompileAndVerify(source +#if NETFRAMEWORK + , expectedOutput: "x => Convert(Int32 Target(Int32).CreateDelegate(System.Func`2[System.Int32,System.Int32], null))" +#else + , expectedOutput: "x => Convert(Int32 Target(Int32).CreateDelegate(System.Func`2[System.Int32,System.Int32], null), Func`2)" +#endif + , symbolValidator: VerifyNoCacheContainersIn("C")); + verifier.VerifyIL("C.Main", @" +{ + // Code size 160 (0xa0) + .maxstack 7 + .locals init (System.Linq.Expressions.ParameterExpression V_0) + IL_0000: ldtoken ""int"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""x"" + IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" + IL_0014: stloc.0 + IL_0015: ldtoken ""int C.Target(int)"" + IL_001a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_001f: castclass ""System.Reflection.MethodInfo"" + IL_0024: ldtoken ""System.Reflection.MethodInfo"" + IL_0029: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_002e: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0033: ldtoken ""System.Delegate System.Reflection.MethodInfo.CreateDelegate(System.Type, object)"" + IL_0038: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_003d: castclass ""System.Reflection.MethodInfo"" + IL_0042: ldc.i4.2 + IL_0043: newarr ""System.Linq.Expressions.Expression"" + IL_0048: dup + IL_0049: ldc.i4.0 + IL_004a: ldtoken ""System.Func"" + IL_004f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0054: ldtoken ""System.Type"" + IL_0059: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_005e: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0063: stelem.ref + IL_0064: dup + IL_0065: ldc.i4.1 + IL_0066: ldnull + IL_0067: ldtoken ""object"" + IL_006c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0071: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0076: stelem.ref + IL_0077: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" + IL_007c: ldtoken ""System.Func"" + IL_0081: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0086: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_008b: ldc.i4.1 + IL_008c: newarr ""System.Linq.Expressions.ParameterExpression"" + IL_0091: dup + IL_0092: ldc.i4.0 + IL_0093: ldloc.0 + IL_0094: stelem.ref + IL_0095: call ""System.Linq.Expressions.Expression>> System.Linq.Expressions.Expression.Lambda>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_009a: call ""void System.Console.WriteLine(object)"" + IL_009f: ret +} +"); + } + + [Fact] + public void Not_InExpressionLamba1() + { + var source = @" +using System; +using System.Linq.Expressions; +class C +{ + public static void Main(string[] args) + { + Func>>> f = x => y => Target; + Console.WriteLine(f(0)); + } + + static int Target(int x) => 0; +} +"; + var verifier = CompileAndVerify(source +#if NETFRAMEWORK + , expectedOutput: "y => Convert(Int32 Target(Int32).CreateDelegate(System.Func`2[System.Int32,System.Int32], null))" +#else + , expectedOutput: "y => Convert(Int32 Target(Int32).CreateDelegate(System.Func`2[System.Int32,System.Int32], null), Func`2)" +#endif + , symbolValidator: VerifyNoCacheContainersIn("C")); + verifier.VerifyIL("C.<>c.
b__0_0", @" +{ + // Code size 155 (0x9b) + .maxstack 7 + .locals init (System.Linq.Expressions.ParameterExpression V_0) + IL_0000: ldtoken ""int"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""y"" + IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" + IL_0014: stloc.0 + IL_0015: ldtoken ""int C.Target(int)"" + IL_001a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_001f: castclass ""System.Reflection.MethodInfo"" + IL_0024: ldtoken ""System.Reflection.MethodInfo"" + IL_0029: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_002e: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0033: ldtoken ""System.Delegate System.Reflection.MethodInfo.CreateDelegate(System.Type, object)"" + IL_0038: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_003d: castclass ""System.Reflection.MethodInfo"" + IL_0042: ldc.i4.2 + IL_0043: newarr ""System.Linq.Expressions.Expression"" + IL_0048: dup + IL_0049: ldc.i4.0 + IL_004a: ldtoken ""System.Func"" + IL_004f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0054: ldtoken ""System.Type"" + IL_0059: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_005e: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0063: stelem.ref + IL_0064: dup + IL_0065: ldc.i4.1 + IL_0066: ldnull + IL_0067: ldtoken ""object"" + IL_006c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0071: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0076: stelem.ref + IL_0077: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" + IL_007c: ldtoken ""System.Func"" + IL_0081: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0086: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_008b: ldc.i4.1 + IL_008c: newarr ""System.Linq.Expressions.ParameterExpression"" + IL_0091: dup + IL_0092: ldc.i4.0 + IL_0093: ldloc.0 + IL_0094: stelem.ref + IL_0095: call ""System.Linq.Expressions.Expression>> System.Linq.Expressions.Expression.Lambda>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_009a: ret +} +"); + } + + [Fact] + public void Not_InStaticConstructor0() + { + var source = @" +using System; +class C +{ + static readonly Action ManualCache = Target; + static void Target() { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyNoCacheContainersIn("C")); + verifier.VerifyIL("C..cctor", @" +{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldnull + IL_0001: ldftn ""void C.Target()"" + IL_0007: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_000c: stsfld ""System.Action C.ManualCache"" + IL_0011: ret +} +"); + } + + [Fact] + public void Not_InStaticConstructor1() + { + var source = @" +using System; +struct C +{ + static readonly Action ManualCache; + static void Target() { } + + static C() + { + ManualCache = Target; + } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyNoCacheContainersIn("C")); + verifier.VerifyIL("C..cctor", @" +{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldnull + IL_0001: ldftn ""void C.Target()"" + IL_0007: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_000c: stsfld ""System.Action C.ManualCache"" + IL_0011: ret +} +"); + } + + [Fact] + public void Not_TargetTypedNew0() + { + var source = @" +using System; + +Action f = new(Target); +f(); + +static void Target() { Console.WriteLine(""PASS""); } +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS, symbolValidator: VerifyNoCacheContainersIn("Program")); + verifier.VerifyIL("", @" +{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldnull + IL_0001: ldftn ""void Program.<
$>g__Target|0_0()"" + IL_0007: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_000c: callvirt ""void System.Action.Invoke()"" + IL_0011: ret +} +"); + } + + [Fact] + public void Not_TargetTypedNew1() + { + var source = @" +#nullable enable +using System; + +Action? f = new(Target); +f(); + +static void Target() { Console.WriteLine(""PASS""); } +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS, symbolValidator: VerifyNoCacheContainersIn("Program")); + verifier.VerifyIL("", @" +{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldnull + IL_0001: ldftn ""void Program.<
$>g__Target|0_0()"" + IL_0007: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_000c: callvirt ""void System.Action.Invoke()"" + IL_0011: ret +} +"); + } + + [Fact] + public void Not_CSharp10() + { + var source = @" +var f = Target; +f(); +static void Target() { } +"; + var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular10, symbolValidator: VerifyNoCacheContainersIn("Program")); + verifier.VerifyIL("", @" +{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldnull + IL_0001: ldftn ""void Program.<
$>g__Target|0_0()"" + IL_0007: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_000c: callvirt ""void System.Action.Invoke()"" + IL_0011: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped_CouldBeModuleScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + Test((Action)Target); + } + + static void Test(Action action) + { + action(); + } + + static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("C.Main", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void C.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action C.<>O.<0>__Target"" + IL_001b: call ""void C.Test(System.Action)"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped_CouldBeModuleScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + var d = new D(); + d.Test()(); + } + + public static void Target() { Console.WriteLine(""PASS""); } +} +class D +{ + public Action Test() + { + return (Action)C.Target; + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void C.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped_CouldBeModuleScoped2() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)E.Target; + t(); + } +} +class E +{ + public static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped_CouldBeModuleScoped3() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)E.Target; + t(0); + } +} +class E +{ + public static void Target(V v) { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(int)"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: ldc.i4.0 + IL_001c: callvirt ""void System.Action.Invoke(int)"" + IL_0021: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped_CouldBeModuleScoped4() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)E.Target; + t(0); + } +} +class E +{ + public static void Target(V v) { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(int)"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: ldc.i4.0 + IL_001c: callvirt ""void System.Action.Invoke(int)"" + IL_0021: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped_CouldBeModuleScoped5() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Func)E.Target; + t(0); + } +} +class E +{ + public static V Target(V v) { Console.WriteLine(""PASS""); return default(V); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldsfld ""System.Func D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int E.Target(int)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func D.<>O.<0>__Target"" + IL_001b: ldc.i4.0 + IL_001c: callvirt ""int System.Func.Invoke(int)"" + IL_0021: pop + IL_0022: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)Target; + t(); + } + + static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void D.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)Target; + t(); + } + + static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void D.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped2() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)Target; + t(); + } + + static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void D.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped3() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)E.Target; + t(); + } +} +class E +{ + public static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped4() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)E.Target; + t(); + } +} +class E +{ + public static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped5() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Func)E.Target; + t(); + } +} +class E +{ + public static N Target() { Console.WriteLine(""PASS""); return default(N); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Func D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""T E.Target()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func D.<>O.<0>__Target"" + IL_001b: callvirt ""T System.Func.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped6() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Func)E.Target; + t(); + } +} +class E +{ + public static V Target() { Console.WriteLine(""PASS""); return default(V); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Func D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int E.Target()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func D.<>O.<0>__Target"" + IL_001b: callvirt ""int System.Func.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_TypeScoped7() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Func)E.Target; + t(default(T)); + } +} +class E +{ + public static V Target(K k) { Console.WriteLine(""PASS""); return default(V); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 43 (0x2b) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldsfld ""System.Func D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int E.Target(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func D.<>O.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""T"" + IL_0023: ldloc.0 + IL_0024: callvirt ""int System.Func.Invoke(T)"" + IL_0029: pop + IL_002a: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_MethodScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + D.Test(); + } + + public static void Target() { Console.WriteLine(""PASS""); } +} +class D +{ + public static void Test() + { + var t = (Action)C.Target; + t(); + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void C.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.O__0_0.<0>__Target"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_MethodScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)E.Target; + t(); + } +} +class E +{ + public static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.O__0_0.<0>__Target"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_MethodScoped2() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Func)E.Target; + t(default(T)); + } +} +class E +{ + public static V Target(K k) { Console.WriteLine(""PASS""); return default(V); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 43 (0x2b) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldsfld ""System.Func D.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int E.Target(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func D.O__0_0.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""T"" + IL_0023: ldloc.0 + IL_0024: callvirt ""int System.Func.Invoke(T)"" + IL_0029: pop + IL_002a: ret +} +"); + } + + [Fact] + public void CacheExplicitConversions_MethodScoped3() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + var t = (Action)E.Target; + t(default(M), default(T)); + } +} +class E +{ + public static void Target(K k, V v) { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 51 (0x33) + .maxstack 3 + .locals init (M V_0, + T V_1) + IL_0000: ldsfld ""System.Action D.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(M, T)"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.O__0_0.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""M"" + IL_0023: ldloc.0 + IL_0024: ldloca.s V_1 + IL_0026: initobj ""T"" + IL_002c: ldloc.1 + IL_002d: callvirt ""void System.Action.Invoke(M, T)"" + IL_0032: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped_CouldBeModuleScoped0() + { + var source = @" +using System; +delegate void MyAction(); +class C +{ + public static void Main(string[] args) + { + MyAction t = Target; + t(); + } + + static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("C.Main", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""MyAction C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void C.Target()"" + IL_0010: newobj ""MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""MyAction C.<>O.<0>__Target"" + IL_001b: callvirt ""void MyAction.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped_CouldBeModuleScoped1() + { + var source = @" +using System; +class C +{ + public delegate void MyAction(); + + public static void Main(string[] args) + { + MyAction t = Target; + t(); + } + + static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("C.Main", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""C.MyAction C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void C.Target()"" + IL_0010: newobj ""C.MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""C.MyAction C.<>O.<0>__Target"" + IL_001b: callvirt ""void C.MyAction.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped0() + { + var source = @" +using System; +delegate void MyAction(); +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + public void Test() + { + MyAction t = Target; + t(); + } + + public static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""MyAction D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void D.Target()"" + IL_0010: newobj ""MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""MyAction D.<>O.<0>__Target"" + IL_001b: callvirt ""void MyAction.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test()(); + } +} +class D +{ + public delegate void MyAction(); + + public MyAction Test() + { + return Target; + } + + static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldsfld ""D.MyAction D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void D.Target()"" + IL_0010: newobj ""D.MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyAction D.<>O.<0>__Target"" + IL_001b: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped2() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + delegate void MyAction(); + + public void Test() + { + MyAction t = Target; + t(); + } + + static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""D.MyAction D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void D.Target()"" + IL_0010: newobj ""D.MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyAction D.<>O.<0>__Target"" + IL_001b: callvirt ""void D.MyAction.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped3() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + delegate void MyAction(); + + public void Test() + { + MyAction t = E.Target; + t(); + } +} +class E +{ + public static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""D.MyAction D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target()"" + IL_0010: newobj ""D.MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyAction D.<>O.<0>__Target"" + IL_001b: callvirt ""void D.MyAction.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped4() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + delegate void MyAction(); + + public void Test() + { + MyAction t = E.Target; + t(); + } +} +class E +{ + public static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""D.MyAction D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target()"" + IL_0010: newobj ""D.MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyAction D.<>O.<0>__Target"" + IL_001b: callvirt ""void D.MyAction.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped5() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + delegate T MyFunc(); + + public void Test() + { + MyFunc t = E.Target; + t(); + } +} +class E +{ + public static V Target() { Console.WriteLine(""PASS""); return default(V); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""D.MyFunc D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""T E.Target()"" + IL_0010: newobj ""D.MyFunc..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyFunc D.<>O.<0>__Target"" + IL_001b: callvirt ""T D.MyFunc.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped6() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + delegate int MyFunc(T i); + + public void Test() + { + MyFunc t = E.Target; + t(default(T)); + } +} +class E +{ + public static V Target(K k) { Console.WriteLine(""PASS""); return default(V); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 43 (0x2b) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldsfld ""D.MyFunc D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int E.Target(T)"" + IL_0010: newobj ""D.MyFunc..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyFunc D.<>O.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""T"" + IL_0023: ldloc.0 + IL_0024: callvirt ""int D.MyFunc.Invoke(T)"" + IL_0029: pop + IL_002a: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped7() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D +{ + delegate T MyFunc(M m); + + public void Test() + { + MyFunc t = E.Target; + t(default(M)); + } +} +class E +{ + public static V Target(K k) { Console.WriteLine(""PASS""); return default(V); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 43 (0x2b) + .maxstack 2 + .locals init (M V_0) + IL_0000: ldsfld ""D.MyFunc D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""T E.Target(M)"" + IL_0010: newobj ""D.MyFunc..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyFunc D.<>O.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""M"" + IL_0023: ldloc.0 + IL_0024: callvirt ""T D.MyFunc.Invoke(M)"" + IL_0029: pop + IL_002a: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_TypeScoped8() + { + var source = @" +using System; +class C +{ + delegate void MyAction(); + + public static void Main(string[] args) + { + MyAction t = Target; + t(); + } + + static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("C.Main", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""C.MyAction C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void C.Target()"" + IL_0010: newobj ""C.MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""C.MyAction C.<>O.<0>__Target"" + IL_001b: callvirt ""void C.MyAction.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_MethodScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } + + public static void Target() { Console.WriteLine(""PASS""); } +} +class D +{ + delegate void MyAction(); + + public void Test() + { + MyAction t = C.Target; + t(); + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""D.MyAction D.O__1_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void C.Target()"" + IL_0010: newobj ""D.MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyAction D.O__1_0.<0>__Target"" + IL_001b: callvirt ""void D.MyAction.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_MethodScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } + + public static void Target(K k) { Console.WriteLine(""PASS""); } +} +class D +{ + delegate void MyAction(M m); + + public void Test() + { + MyAction t = C.Target; + t(default(V)); + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 42 (0x2a) + .maxstack 2 + .locals init (V V_0) + IL_0000: ldsfld ""D.MyAction D.O__1_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void C.Target(V)"" + IL_0010: newobj ""D.MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyAction D.O__1_0.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""V"" + IL_0023: ldloc.0 + IL_0024: callvirt ""void D.MyAction.Invoke(V)"" + IL_0029: ret +} +"); + } + + [Fact] + public void CacheImplicitConversions_MethodScoped2() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } + + public static N Target(K k, N n) { Console.WriteLine(""PASS""); return default(N); } +} +class D +{ + delegate V MyFunc(M m, V v); + + public void Test() + { + MyFunc t = C.Target; + t(default(T), default(V)); + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 52 (0x34) + .maxstack 3 + .locals init (T V_0, + V V_1) + IL_0000: ldsfld ""D.MyFunc D.O__1_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""V C.Target(T, V)"" + IL_0010: newobj ""D.MyFunc..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyFunc D.O__1_0.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""T"" + IL_0023: ldloc.0 + IL_0024: ldloca.s V_1 + IL_0026: initobj ""V"" + IL_002c: ldloc.1 + IL_002d: callvirt ""V D.MyFunc.Invoke(T, V)"" + IL_0032: pop + IL_0033: ret +} +"); + } + + [Fact] + public void Where_TypeScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(); + } +} +class D where T : C +{ + delegate void MyAction(T t); + + public void Test() + { + MyAction t = E.Target; + t(null); + } +} +class E +{ + public static void Target(N n) { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.Test", @" +{ + // Code size 42 (0x2a) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldsfld ""D.MyAction D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(C)"" + IL_0010: newobj ""D.MyAction..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyAction D.<>O.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""T"" + IL_0023: ldloc.0 + IL_0024: callvirt ""void D.MyAction.Invoke(T)"" + IL_0029: ret +} +"); + } + + [Fact] + public void Where_MethodScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(new C()); + } +} +class D where T : C +{ + delegate T MyFunc(); + + public void Test(M m) where M : T + { + MyFunc t = E.Target; + t(); + } +} +class E +{ + public static N Target() { Console.WriteLine(""PASS""); return default(N); } +} +"; + static void containerValidator(ModuleSymbol module) + { + var testClass = module.GlobalNamespace.GetTypeMember("D"); + var container = testClass.GetTypeMember("O__1_0"); + AssertEx.NotNull(container); + + var typeParameters = container.TypeParameters; + Assert.Equal(1, container.TypeParameters.Length); + + var m = typeParameters[0]; + Assert.Equal(1, m.ConstraintTypes().Length); + Assert.Equal(testClass.TypeParameters[0], m.ConstraintTypes()[0]); + } + CompileAndVerify(source, symbolValidator: containerValidator, expectedOutput: PASS).VerifyIL("D.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""D.MyFunc D.O__1_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""M E.Target()"" + IL_0010: newobj ""D.MyFunc..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyFunc D.O__1_0.<0>__Target"" + IL_001b: callvirt ""T D.MyFunc.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void Where_MethodScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(new C()); + } +} +class D +{ + delegate C MyFunc(); + + public void Test(M m) where M : C + { + MyFunc t = E.Target; + t(); + } +} +class E +{ + public static N Target() { Console.WriteLine(""PASS""); return default(N); } +} +"; + static void containerValidator(ModuleSymbol module) + { + var globalNs = module.GlobalNamespace; + var mainClass = globalNs.GetTypeMember("C"); + var container = globalNs.GetMember("D.O__1_0"); + AssertEx.NotNull(container); + + var typeParameters = container.TypeParameters; + Assert.Equal(1, container.TypeParameters.Length); + + var m = typeParameters[0]; + Assert.Equal(1, m.ConstraintTypes().Length); + Assert.Equal(mainClass, m.ConstraintTypes()[0]); + } + CompileAndVerify(source, symbolValidator: containerValidator, expectedOutput: PASS).VerifyIL("D.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""D.MyFunc D.O__1_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""M E.Target()"" + IL_0010: newobj ""D.MyFunc..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyFunc D.O__1_0.<0>__Target"" + IL_001b: callvirt ""C D.MyFunc.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void Where_MethodScoped2() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + (new D()).Test(0); + } +} +class D +{ + public void Test(M m) where M : struct + { + Func t = E.Target; + t(); + } +} +class E +{ + public static N Target() { Console.WriteLine(""PASS""); return default(N); } +} +"; + static void containerValidator(ModuleSymbol module) + { + var container = module.GlobalNamespace.GetMember("D.O__0_0"); + AssertEx.NotNull(container); + + var typeParameters = container.TypeParameters; + Assert.Equal(1, container.TypeParameters.Length); + + var m = typeParameters[0]; + AssertEx.NotNull(m); + Assert.True(m.IsValueType); + } + CompileAndVerify(source, symbolValidator: containerValidator, expectedOutput: PASS).VerifyIL("D.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Func D.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""M? E.Target()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func D.O__0_0.<0>__Target"" + IL_001b: callvirt ""M? System.Func.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void ExtensionMethod_TypeScoped_CouldBeModuleScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + var t = (Action)E.Target; + t(null); + } +} +static class E +{ + public static void Target(this C c) { Console.WriteLine(""PASS""); } +} +"; + CompileAndVerify(source, expectedOutput: PASS).VerifyIL("C.Main", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(C)"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action C.<>O.<0>__Target"" + IL_001b: ldnull + IL_001c: callvirt ""void System.Action.Invoke(C)"" + IL_0021: ret +} +"); + } + + [Fact] + public void ExtensionMethod_TypeScoped_CouldBeModuleScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + Action t = E.Target; + t(null); + } +} +static class E +{ + public static void Target(this T t) { Console.WriteLine(""PASS""); } +} +"; + CompileAndVerify(source, expectedOutput: PASS).VerifyIL("C.Main", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(C)"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action C.<>O.<0>__Target"" + IL_001b: ldnull + IL_001c: callvirt ""void System.Action.Invoke(C)"" + IL_0021: ret +} +"); + } + + [Fact] + public void ExtensionMethod_TypeScoped_CouldBeModuleScoped2() + { + var source = @" +using System; +static class E +{ + static void Test() + { + Action t = Target; + } + + public static void Target(this T t) { } +} +"; + CompileAndVerify(source).VerifyIL("E.Test", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action E.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void E.Target(int)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action E.<>O.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void ExtensionMethod_TypeScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + D.Test(); + } +} +class D where T : C +{ + public static void Test() + { + var t = (Action)E.Target; + t(null); + } +} +static class E +{ + public static void Target(this C c) { Console.WriteLine(""PASS""); } +} +"; + CompileAndVerify(source, expectedOutput: PASS).VerifyIL("D.Test", @" +{ + // Code size 42 (0x2a) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(C)"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""T"" + IL_0023: ldloc.0 + IL_0024: callvirt ""void System.Action.Invoke(T)"" + IL_0029: ret +} +"); + } + + [Fact] + public void ExtensionMethod_TypeScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + D.Test(0); + } +} +class D +{ + public static void Test(K k) + { + Action t = E.Target; + t(k); + } +} +static class E +{ + public static void Target(this T t) { Console.WriteLine(""PASS""); } +} +"; + CompileAndVerify(source, expectedOutput: PASS).VerifyIL("D.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Action D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(K)"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action D.<>O.<0>__Target"" + IL_001b: ldarg.0 + IL_001c: callvirt ""void System.Action.Invoke(K)"" + IL_0021: ret +} +"); + } + + [Fact] + public void ExtensionMethod_TypeScoped2() + { + var source = @" +using System; +static class E +{ + class F + { + void Test() + { + Action t = Target; + } + } + + public static void Target(this T t) { } +} +"; + CompileAndVerify(source).VerifyIL("E.F.Test", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action E.F.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void E.Target(T)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action E.F.<>O.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void ExtensionMethod_MethodScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + Test(0); + } + + static void Test(T arg) + { + var t = (Action)E.Target; + t(arg); + } +} +static class E +{ + public static void Target(this M m) { Console.WriteLine(""PASS""); } +} +"; + CompileAndVerify(source, expectedOutput: PASS).VerifyIL("C.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__1_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(T)"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action C.O__1_0.<0>__Target"" + IL_001b: ldarg.0 + IL_001c: callvirt ""void System.Action.Invoke(T)"" + IL_0021: ret +} +"); + } + + [Fact] + public void ExtensionMethod_MethodScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + Test(); + } + + static void Test() where T : C + { + var t = (Action)E.Target; + t(null); + } +} +static class E +{ + public static void Target(this C c) { Console.WriteLine(""PASS""); } +} +"; + CompileAndVerify(source, expectedOutput: PASS).VerifyIL("C.Test", @" +{ + // Code size 42 (0x2a) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldsfld ""System.Action C.O__1_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.Target(C)"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action C.O__1_0.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""T"" + IL_0023: ldloc.0 + IL_0024: callvirt ""void System.Action.Invoke(T)"" + IL_0029: ret +} +"); + } + + [Fact] + public void ExtensionMethod_MethodScoped2() + { + var source = @" +using System; +static class E +{ + static void Test() + { + Action t = Target; + } + + public static void Target(this T t) { } +} +"; + CompileAndVerify(source).VerifyIL("E.Test", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action E.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void E.Target(T)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action E.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void Lambda_TypeScoped_CouldBeModuleScoped0() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + Action test = () => Invoke(Target); + test(); + } + + static void Invoke(Action a) => a(); + + static void Target() => Console.WriteLine(""PASS""); +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("C.<>c.
b__0_0", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void C.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action C.<>O.<0>__Target"" + IL_001b: call ""void C.Invoke(System.Action)"" + IL_0020: ret +} +"); + } + + [Fact] + public void Lambda_TypeScoped_CouldBeModuleScoped1() + { + var source = @" +using System; +class C +{ + public static void Main(string[] args) + { + Action test = () => ((Action)D.Target)(); + test(); + } +} +class D +{ + public static void Target() { Console.WriteLine(""PASS""); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("C.<>c.
b__0_0", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void D.Target()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action C.<>O.<0>__Target"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void Lambda_TypeScoped0() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) + { + D.Test(); + } +} +class D +{ + public static void Test() + { + Action test = () => + { + ((Func)Target)(); + }; + test(); + } + + static T Target() { Console.WriteLine(""PASS""); return default(T); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.<>c.b__0_0", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Func D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""T D.Target()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func D.<>O.<0>__Target"" + IL_001b: callvirt ""T System.Func.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void Lambda_TypeScoped1() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) + { + D.Test(); + } +} +class D +{ + delegate T MyFunc(); + public static void Test() + { + Func a = () => E.Target; + a()(); + } +} +class E +{ + public static V Target() { Console.WriteLine(""PASS""); return default(V); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.<>c.b__1_0", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldsfld ""D.MyFunc D.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""T E.Target()"" + IL_0010: newobj ""D.MyFunc..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D.MyFunc D.<>O.<0>__Target"" + IL_001b: ret +} +"); + } + + [Fact] + public void Lambda_MethodScoped0() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) + { + D.Test(0); + } +} +class D +{ + public static void Test(G g) + { + Action test = () => + { + ((Func)Target)(); + }; + test(); + } + + static T Target() { Console.WriteLine(""PASS""); return default(T); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.<>c__0.b__0_0", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Func D.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""T D.Target()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func D.O__0_0.<0>__Target"" + IL_001b: callvirt ""T System.Func.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void Lambda_MethodScoped1() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) + { + D.Test(0); + } +} +class D +{ + public static void Test(G g) + { + Func> a = () => E.Target; + a()(); + } +} +class E +{ + public static V Target() { Console.WriteLine(""PASS""); return default(V); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS); + verifier.VerifyIL("D.<>c__0.b__0_0", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldsfld ""System.Func D.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""G E.Target()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func D.O__0_0.<0>__Target"" + IL_001b: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_TypeScoped0() + { + var source = @" +using System; +class C +{ + void Test0() { var t = (Action)D.Target; } + void Test1() { Action t = D.Target; } +} +class D +{ + public static void Target() { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.<>O", arity: 0 + , "System.Action <0>__Target" + )); + verifier.VerifyIL("C.Test0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void D.Target()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.<>O.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.Test1", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void D.Target()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.<>O.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_TypeScoped1() + { + var source = @" +using System; +class C +{ + void Test0() { var t = (Func)Target; } + void Test1() { Func t = Target; } + static V Target() { return default(V); } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.<>O", arity: 0 + , "System.Func <0>__Target" + )); + verifier.VerifyIL("C.Test0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""T C.Target()"" + IL_000e: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func C.<>O.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.Test1", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""T C.Target()"" + IL_000e: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func C.<>O.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_TypeScoped2() + { + var source = @" +using System; +class C +{ + delegate T MyFunc(); + void Test0() { var t = (MyFunc)Target; } + void Test1() { MyFunc t = Target; } + static T Target() { return default(T); } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.<>O", arity: 0 + , "C.MyFunc <0>__Target" + )); + verifier.VerifyIL("C.Test0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""C.MyFunc C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""T C.Target()"" + IL_000e: newobj ""C.MyFunc..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""C.MyFunc C.<>O.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.Test1", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""C.MyFunc C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""T C.Target()"" + IL_000e: newobj ""C.MyFunc..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""C.MyFunc C.<>O.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_TypeScoped3_CLRSignature() + { + var source = @" +#nullable enable +using System; +class C +{ + void Test0() { var t = (Func)Target; } + void Test1() { Func t = Target; } + static V Target() { return default(V); } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.<>O", arity: 0 + , "System.Func <0>__Target" + )); + verifier.VerifyIL("C.Test0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""T C.Target()"" + IL_000e: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func C.<>O.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.Test1", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""T C.Target()"" + IL_000e: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func C.<>O.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_TypeScoped4_CLRSignature() + { + var source = @" +using System; +class C +{ + void Test0() { var t = (Func<(T x, T y)>)Target<(T x, T y)>; } + void Test1() { Func<(T a, T b)> t = Target<(T c, T d)>; } + static V Target() { return default(V); } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.<>O", arity: 0 + , "System.Func<(T x, T y)> <0>__Target" + )); + verifier.VerifyIL("C.Test0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func> C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""System.ValueTuple C.Target>()"" + IL_000e: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func> C.<>O.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.Test1", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func> C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""System.ValueTuple C.Target>()"" + IL_000e: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func> C.<>O.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_TypeScoped5_AnonymousDelegate() + { + var source = @" +class C +{ + void Test0(T t) { G0(Target); } + void Test1(T t) { G1(Target); } + + void G0(System.Delegate d) { } + void G1(System.Delegate d) { } + + static dynamic Target(ref G g) => 0; +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.<>O", arity: 0 + , "<>F{00000001} <0>__Target" + )); + verifier.VerifyIL("C.Test0", @" +{ + // Code size 34 (0x22) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldsfld "" C.<>O.<0>__Target"" + IL_0006: dup + IL_0007: brtrue.s IL_001c + IL_0009: pop + IL_000a: ldnull + IL_000b: ldftn ""dynamic C.Target(ref int)"" + IL_0011: newobj ""<>F{00000001}..ctor(object, System.IntPtr)"" + IL_0016: dup + IL_0017: stsfld "" C.<>O.<0>__Target"" + IL_001c: call ""void C.G0(System.Delegate)"" + IL_0021: ret +} +"); + verifier.VerifyIL("C.Test1", @" +{ + // Code size 34 (0x22) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldsfld "" C.<>O.<0>__Target"" + IL_0006: dup + IL_0007: brtrue.s IL_001c + IL_0009: pop + IL_000a: ldnull + IL_000b: ldftn ""dynamic C.Target(ref int)"" + IL_0011: newobj ""<>F{00000001}..ctor(object, System.IntPtr)"" + IL_0016: dup + IL_0017: stsfld "" C.<>O.<0>__Target"" + IL_001c: call ""void C.G1(System.Delegate)"" + IL_0021: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_MethodScoped0() + { + var source = @" +using System; +class C +{ + void Test() + { + var t0 = (Action)D.Target; + Action t1 = D.Target; + } +} +class D +{ + public static void Target() { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.O__0_0", arity: 1 + , "System.Action <0>__Target" + )); + verifier.VerifyIL("C.Test", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void D.Target()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0018: ldsfld ""System.Action C.O__0_0.<0>__Target"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""void D.Target()"" + IL_0026: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0030: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_MethodScoped1() + { + var source = @" +using System; +class C +{ + void Test() + { + var t0 = (Func)D.Target; + Func t1 = D.Target; + } +} +class D +{ + public static B Target(H h) => default(B); +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.O__0_0", arity: 1 + , "System.Func <0>__Target" + )); + verifier.VerifyIL("C.Test", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""V D.Target(T)"" + IL_000e: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0018: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""V D.Target(T)"" + IL_0026: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0030: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_MethodScoped2() + { + var source = @" +using System; +class C +{ + delegate O MyFunc(int num); + class O { } + void Test() where V : O + { + var t0 = (MyFunc)D.Target; + MyFunc t1 = D.Target; + } +} +static class D +{ + public static B Target(this int num) => default(B); +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.O__2_0", arity: 1 + , "C.MyFunc <0>__Target" + )); + verifier.VerifyIL("C.Test", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""C.MyFunc C.O__2_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""V D.Target(int)"" + IL_000e: newobj ""C.MyFunc..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""C.MyFunc C.O__2_0.<0>__Target"" + IL_0018: ldsfld ""C.MyFunc C.O__2_0.<0>__Target"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""V D.Target(int)"" + IL_0026: newobj ""C.MyFunc..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""C.MyFunc C.O__2_0.<0>__Target"" + IL_0030: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_MethodScoped3_CLRSignature() + { + var source = @" +using System; +class C +{ + void Test() + { + var t0 = (Func)D.Target; + Func t1 = D.Target; + } +} +class D +{ + public static B Target(dynamic o, H h) => default(B); +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.O__0_0", arity: 1 + , "System.Func <0>__Target" + )); + verifier.VerifyIL("C.Test", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""V D.Target(dynamic, T)"" + IL_000e: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0018: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""V D.Target(dynamic, T)"" + IL_0026: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0030: ret +} +"); + } + + [Fact] + public void SameTypeAndSymbolResultsSameField_MethodScoped4_AnonymousDelegate() + { + var source = @" +class C +{ + void Test(T t) + { + G0(Target); + G1(Target); + } + + void G0(System.Delegate d) { } + void G1(System.Delegate d) { } + + static dynamic Target(ref G g) => 0; +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.O__0_0", arity: 1 + , "<>F{00000001} <0>__Target" + )); + verifier.VerifyIL("C.Test", @" +{ + // Code size 67 (0x43) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldsfld "" C.O__0_0.<0>__Target"" + IL_0006: dup + IL_0007: brtrue.s IL_001c + IL_0009: pop + IL_000a: ldnull + IL_000b: ldftn ""dynamic C.Target(ref T)"" + IL_0011: newobj ""<>F{00000001}..ctor(object, System.IntPtr)"" + IL_0016: dup + IL_0017: stsfld "" C.O__0_0.<0>__Target"" + IL_001c: call ""void C.G0(System.Delegate)"" + IL_0021: ldarg.0 + IL_0022: ldsfld "" C.O__0_0.<0>__Target"" + IL_0027: dup + IL_0028: brtrue.s IL_003d + IL_002a: pop + IL_002b: ldnull + IL_002c: ldftn ""dynamic C.Target(ref T)"" + IL_0032: newobj ""<>F{00000001}..ctor(object, System.IntPtr)"" + IL_0037: dup + IL_0038: stsfld "" C.O__0_0.<0>__Target"" + IL_003d: call ""void C.G1(System.Delegate)"" + IL_0042: ret +} +"); + } + + [Fact] + public void ContainersCanBeShared_TypeScoped0() + { + var source = @" +using System; +class A +{ + class B + { + void Test0() + { + Action t0 = Target0; + Action t1 = Target1; + } + + void Test1() + { + Action t1 = Target1; + Action t2 = D.Target2; + } + + void Test2() + { + Action t2 = D.Target2; + Action t3 = D.Target3; + } + + void Test3() + { + Action t3 = D.Target3; + Action t4 = D.E.Target4; + } + + void Test4() + { + Action t4 = D.E.Target4; + Action t5 = E.Target5; + } + + void Test5() + { + Action t5t = E.Target5; + Action t5v = E.Target5; + } + + static void Target0(T t) { } + } + + static void Target1(T t) { } +} +class D +{ + public static void Target2(K k) { } + + public static void Target3(K k, M m) { } + + public class E

+ { + public static void Target4(K k, P p) { } + } +} +static class E +{ + public static void Target5(this N n) { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("A.B.<>O", arity: 0 + , "System.Action <0>__Target0" + , "System.Action <1>__Target1" + , "System.Action <2>__Target2" + , "System.Action <3>__Target3" + , "System.Action <4>__Target4" + , "System.Action <5>__Target5" + , "System.Action <6>__Target5" + )); + verifier.VerifyIL("A.B.Test0", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""System.Action A.B.<>O.<0>__Target0"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void A.B.Target0(T)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action A.B.<>O.<0>__Target0"" + IL_0018: ldsfld ""System.Action A.B.<>O.<1>__Target1"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""void A.Target1(T)"" + IL_0026: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Action A.B.<>O.<1>__Target1"" + IL_0030: ret +} +"); + verifier.VerifyIL("A.B.Test1", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""System.Action A.B.<>O.<1>__Target1"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void A.Target1(T)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action A.B.<>O.<1>__Target1"" + IL_0018: ldsfld ""System.Action A.B.<>O.<2>__Target2"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""void D.Target2(T)"" + IL_0026: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Action A.B.<>O.<2>__Target2"" + IL_0030: ret +} +"); + verifier.VerifyIL("A.B.Test2", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""System.Action A.B.<>O.<2>__Target2"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void D.Target2(T)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action A.B.<>O.<2>__Target2"" + IL_0018: ldsfld ""System.Action A.B.<>O.<3>__Target3"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""void D.Target3(T, V)"" + IL_0026: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Action A.B.<>O.<3>__Target3"" + IL_0030: ret +} +"); + verifier.VerifyIL("A.B.Test3", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""System.Action A.B.<>O.<3>__Target3"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void D.Target3(T, V)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action A.B.<>O.<3>__Target3"" + IL_0018: ldsfld ""System.Action A.B.<>O.<4>__Target4"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""void D.E.Target4(T, V)"" + IL_0026: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Action A.B.<>O.<4>__Target4"" + IL_0030: ret +} +"); + verifier.VerifyIL("A.B.Test4", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""System.Action A.B.<>O.<4>__Target4"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void D.E.Target4(T, V)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action A.B.<>O.<4>__Target4"" + IL_0018: ldsfld ""System.Action A.B.<>O.<5>__Target5"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""void E.Target5(T)"" + IL_0026: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Action A.B.<>O.<5>__Target5"" + IL_0030: ret +} +"); + verifier.VerifyIL("A.B.Test5", @" +{ + // Code size 49 (0x31) + .maxstack 2 + IL_0000: ldsfld ""System.Action A.B.<>O.<5>__Target5"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void E.Target5(T)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action A.B.<>O.<5>__Target5"" + IL_0018: ldsfld ""System.Action A.B.<>O.<6>__Target5"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""void E.Target5(V)"" + IL_0026: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Action A.B.<>O.<6>__Target5"" + IL_0030: ret +} +"); + } + + [Fact] + public void ContainersCanBeShared_MethodScoped0() + { + var source = @" +using System; +class C +{ + void Test() + { + Action a = Target0; + Action b = Target1; + Action c = D.Target2; + Action d = E.Target3; + } + + static void Target0() { } + static void Target1(T t) { } + + class D + { + public static void Target2() { } + } +} +static class E +{ + public static void Target3(this C c) { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.O__0_0", arity: 1 + , "System.Action <0>__Target0" + , "System.Action <1>__Target1" + , "System.Action <2>__Target2" + , "System.Action <3>__Target3" + )); + verifier.VerifyIL("C.Test", @" +{ + // Code size 97 (0x61) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__0_0.<0>__Target0"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.Target0()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__0_0.<0>__Target0"" + IL_0018: ldsfld ""System.Action C.O__0_0.<1>__Target1"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""void C.Target1(T)"" + IL_0026: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Action C.O__0_0.<1>__Target1"" + IL_0030: ldsfld ""System.Action C.O__0_0.<2>__Target2"" + IL_0035: brtrue.s IL_0048 + IL_0037: ldnull + IL_0038: ldftn ""void C.D.Target2()"" + IL_003e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0043: stsfld ""System.Action C.O__0_0.<2>__Target2"" + IL_0048: ldsfld ""System.Action C.O__0_0.<3>__Target3"" + IL_004d: brtrue.s IL_0060 + IL_004f: ldnull + IL_0050: ldftn ""void E.Target3(C)"" + IL_0056: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_005b: stsfld ""System.Action C.O__0_0.<3>__Target3"" + IL_0060: ret +} +"); + } + + [Fact] + public void ContainersCanBeShared_MethodScoped1() + { + var source = @" +using System; +class C +{ + public static void Target0() { } + public static void Target1(T t) { } + + public class D + { + public static void Target2() { } + } +} +static class E +{ + static void Test() + { + Action a = C.Target0; + Action b = C.Target1; + Action c = C.D.Target2; + Action d = Target3; + } + + public static void Target3(this C c) { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("E.O__0_0", arity: 1 + , "System.Action <0>__Target0" + , "System.Action <1>__Target1" + , "System.Action <2>__Target2" + , "System.Action <3>__Target3" + )); + verifier.VerifyIL("E.Test", @" +{ + // Code size 97 (0x61) + .maxstack 2 + IL_0000: ldsfld ""System.Action E.O__0_0.<0>__Target0"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.Target0()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action E.O__0_0.<0>__Target0"" + IL_0018: ldsfld ""System.Action E.O__0_0.<1>__Target1"" + IL_001d: brtrue.s IL_0030 + IL_001f: ldnull + IL_0020: ldftn ""void C.Target1(T)"" + IL_0026: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002b: stsfld ""System.Action E.O__0_0.<1>__Target1"" + IL_0030: ldsfld ""System.Action E.O__0_0.<2>__Target2"" + IL_0035: brtrue.s IL_0048 + IL_0037: ldnull + IL_0038: ldftn ""void C.D.Target2()"" + IL_003e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0043: stsfld ""System.Action E.O__0_0.<2>__Target2"" + IL_0048: ldsfld ""System.Action E.O__0_0.<3>__Target3"" + IL_004d: brtrue.s IL_0060 + IL_004f: ldnull + IL_0050: ldftn ""void E.Target3(C)"" + IL_0056: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_005b: stsfld ""System.Action E.O__0_0.<3>__Target3"" + IL_0060: ret +} +"); + } + + [Fact] + public void ContainersCanBeShared_SkippingUnused() + { + var source = @" +using System; +class C +{ + public static void Target(T t) { } +} +static class E +{ + static void Test() + { + void LF2() + { + void LF3() + { + Action d = C.Target; + static void LF4 () { Action d = C.Target; } + + LF4(); + } + + void LF5() + { + Action d = C.Target; + } + + LF3(); LF5(); + } + + LF2(); + } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("E.O__0_0", arity: 1 + , "System.Action <0>__Target" + )); + verifier.VerifyIL("E.g__LF3|0_1", @" +{ + // Code size 30 (0x1e) + .maxstack 2 + IL_0000: ldsfld ""System.Action E.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.Target(T)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action E.O__0_0.<0>__Target"" + IL_0018: call ""void E.g__LF4|0_3()"" + IL_001d: ret +} +"); + verifier.VerifyIL("E.g__LF4|0_3", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action E.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.Target(T)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action E.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("E.g__LF5|0_2", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action E.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.Target(T)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action E.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void ContainersCanBeShared_LocalFunctions() + { + var source = @" +using System; +static class E +{ + static void Test() + { + void Owner() + { + void LF1() + { + Action d = LF2; + static void LF2() { Console.Write(""PA""); } + + d(); + } + + void LF3() + { + Action d = LF2; + static void LF2() { Console.Write(""SS""); } + + d(); + } + + LF1(); LF3(); + } + + Owner(); + } + + static void Main(string[] args) { Test(); } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: PASS, symbolValidator: VerifyCacheContainer("E.O__0_0", arity: 2 + , "System.Action <0>__LF2" + , "System.Action <1>__LF2" + )); + verifier.VerifyIL("E.g__LF1|0_1", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action E.O__0_0.<0>__LF2"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.g__LF2|0_3()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action E.O__0_0.<0>__LF2"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + verifier.VerifyIL("E.g__LF3|0_2", @" +{ + // Code size 33 (0x21) + .maxstack 2 + IL_0000: ldsfld ""System.Action E.O__0_0.<1>__LF2"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void E.g__LF2|0_4()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action E.O__0_0.<1>__LF2"" + IL_001b: callvirt ""void System.Action.Invoke()"" + IL_0020: ret +} +"); + } + + [Fact] + public void NameAmbiguity_Containers0() + { + var source = @" +void Owner(int i) +{ + var f = Target; +} +void X() +{ + void Owner(string s) + { + var f = Target; + } +} +static void Target() { } +"; + var verifier = CompileAndVerify(source, symbolValidator: static module => + { + VerifyCacheContainer("Program.O__0_0", arity: 1, "System.Action <0>__Target")(module); + VerifyCacheContainer("Program.O__0_1", arity: 1, "System.Action <0>__Target")(module); + }); + verifier.VerifyIL("Program.<

$>g__Owner|0_0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action Program.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void Program.<
$>g__Target|0_2()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action Program.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("Program.<
$>g__Owner|0_3", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action Program.O__0_1.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void Program.<
$>g__Target|0_2()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action Program.O__0_1.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void NameAmbiguity_Containers1() + { + var source = @" +class C +{ + void Owner(int i) + { + var f = Target; + } + void Owner(string s) + { + var f = Target; + } + static void Target() { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: static module => + { + VerifyCacheContainer("C.O__0_0", arity: 1, "System.Action <0>__Target")(module); + VerifyCacheContainer("C.O__1_0", arity: 1, "System.Action <0>__Target")(module); + }); + verifier.VerifyIL("C.Owner(int)", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.Target()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.Owner(string)", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__1_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.Target()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__1_0.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void NameAmbiguity_Containers2() + { + var source = @" +class C +{ + void Owner(int i) + { + var f = Target; + } + void F() + { + void Owner(string s) + { + var f = Target; + } + } + static void Target() { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: static module => + { + VerifyCacheContainer("C.O__0_0", arity: 1, "System.Action <0>__Target")(module); + VerifyCacheContainer("C.O__1_0", arity: 1, "System.Action <0>__Target")(module); + }); + verifier.VerifyIL("C.Owner(int)", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.Target()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.g__Owner|1_0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__1_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.Target()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__1_0.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void NameAmbiguity_Fields0() + { + var source = @" +void F0() +{ + var f = Target; + static void Target() { } +} +void F1() +{ + var f = Target; + static void Target() { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("Program.<>O", arity: 0 + , "System.Action <0>__Target" + , "System.Action <1>__Target" + )); + verifier.VerifyIL("Program.<
$>g__F0|0_0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action Program.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void Program.<
$>g__Target|0_2()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action Program.<>O.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("Program.<
$>g__F1|0_1", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action Program.<>O.<1>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void Program.<
$>g__Target|0_3()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action Program.<>O.<1>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void NameAmbiguity_Fields2() + { + var source = @" +class C +{ + void F() + { + void Owner() + { + void F0() + { + var f = Target; + static void Target() { } + } + void F1() + { + var f = Target; + static void Target() { } + } + } + } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.O__0_0", arity: 1 + , "System.Action <0>__Target" + , "System.Action <1>__Target" + )); + verifier.VerifyIL("C.g__F0|0_1", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.g__Target|0_3()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.g__F1|0_2", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__0_0.<1>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.g__Target|0_4()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__0_0.<1>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void NameAmbiguity_Fields3() + { + var source = @" +using System; +class C +{ + void F() + { + void Owner() + { + Action f = E.Target; + + void F1() + { + Action f = E.Target; + } + } + } +} +class E +{ + public static void Target(int i) { } + public static void Target(string i) { } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.O__0_0", arity: 1 + , "System.Action <0>__Target" + , "System.Action <1>__Target" + )); + verifier.VerifyIL("C.g__Owner|0_0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void E.Target(int)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.g__F1|0_1", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.O__0_0.<1>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void E.Target(string)"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.O__0_0.<1>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void NameAmbiguity_Fields1() + { + var source = @" +class C +{ + void F0() + { + var f = Target; + static void Target() { } + } + void F1() + { + var f = Target; + static void Target() { } + } +} +"; + var verifier = CompileAndVerify(source, symbolValidator: VerifyCacheContainer("C.<>O", arity: 0 + , "System.Action <0>__Target" + , "System.Action <1>__Target" + )); + verifier.VerifyIL("C.F0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.g__Target|0_0()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.<>O.<0>__Target"" + IL_0018: ret +} +"); + verifier.VerifyIL("C.F1", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Action C.<>O.<1>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""void C.g__Target|1_0()"" + IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Action C.<>O.<1>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void EventHandlers_TypeScoped_CouldBeModuleScoped0() + { + var source = @" +using System; +using System.Reflection; +class C +{ + void Test() + { + AppDomain.CurrentDomain.AssemblyResolve += Target; + } + + static Assembly Target(object sender, ResolveEventArgs e) => null; +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 38 (0x26) + .maxstack 3 + IL_0000: call ""System.AppDomain System.AppDomain.CurrentDomain.get"" + IL_0005: ldsfld ""System.ResolveEventHandler C.<>O.<0>__Target"" + IL_000a: dup + IL_000b: brtrue.s IL_0020 + IL_000d: pop + IL_000e: ldnull + IL_000f: ldftn ""System.Reflection.Assembly C.Target(object, System.ResolveEventArgs)"" + IL_0015: newobj ""System.ResolveEventHandler..ctor(object, System.IntPtr)"" + IL_001a: dup + IL_001b: stsfld ""System.ResolveEventHandler C.<>O.<0>__Target"" + IL_0020: callvirt ""void System.AppDomain.AssemblyResolve.add"" + IL_0025: ret +} +"); + } + + [Fact] + public void EventHandlers_TypeScoped_CouldBeModuleScoped1() + { + var source = @" +using System; +class MyEventArgs : EventArgs { } +class C where TEventArgs : EventArgs +{ + event EventHandler SomethingHappened; + + void Test() + { + var c = new C(); + c.SomethingHappened += D.Target; + } + +} +class D +{ + public static void Target(object sender, MyEventArgs e) { } +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 38 (0x26) + .maxstack 3 + IL_0000: newobj ""C..ctor()"" + IL_0005: ldsfld ""System.EventHandler C.<>O.<0>__Target"" + IL_000a: dup + IL_000b: brtrue.s IL_0020 + IL_000d: pop + IL_000e: ldnull + IL_000f: ldftn ""void D.Target(object, MyEventArgs)"" + IL_0015: newobj ""System.EventHandler..ctor(object, System.IntPtr)"" + IL_001a: dup + IL_001b: stsfld ""System.EventHandler C.<>O.<0>__Target"" + IL_0020: callvirt ""void C.SomethingHappened.add"" + IL_0025: ret +} +"); + } + + [Fact] + public void EventHandlers_TypeScoped0() + { + var source = @" +using System; +class C where TEventArgs : EventArgs +{ + event EventHandler SomethingHappened; + + void Test() + { + this.SomethingHappened += Target; + } + + static void Target(object sender, TEventArgs e) { } +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 34 (0x22) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldsfld ""System.EventHandler C.<>O.<0>__Target"" + IL_0006: dup + IL_0007: brtrue.s IL_001c + IL_0009: pop + IL_000a: ldnull + IL_000b: ldftn ""void C.Target(object, TEventArgs)"" + IL_0011: newobj ""System.EventHandler..ctor(object, System.IntPtr)"" + IL_0016: dup + IL_0017: stsfld ""System.EventHandler C.<>O.<0>__Target"" + IL_001c: call ""void C.SomethingHappened.add"" + IL_0021: ret +} +"); + } + + [Fact] + public void EventHandlers_MethodScoped0() + { + var source = @" +using System; +class C +{ + void Test() where TEventArgs : EventArgs + { + var d = new D(); + d.SomethingHappened += Target; + } + + static void Target(object sender, TEventArgs e) where TEventArgs : EventArgs { } +} +class D where TEventArgs : EventArgs +{ + public event EventHandler SomethingHappened; +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 38 (0x26) + .maxstack 3 + IL_0000: newobj ""D..ctor()"" + IL_0005: ldsfld ""System.EventHandler C.O__0_0.<0>__Target"" + IL_000a: dup + IL_000b: brtrue.s IL_0020 + IL_000d: pop + IL_000e: ldnull + IL_000f: ldftn ""void C.Target(object, TEventArgs)"" + IL_0015: newobj ""System.EventHandler..ctor(object, System.IntPtr)"" + IL_001a: dup + IL_001b: stsfld ""System.EventHandler C.O__0_0.<0>__Target"" + IL_0020: callvirt ""void D.SomethingHappened.add"" + IL_0025: ret +} +"); + } + + [Fact] + public void AnonymousTypes_TypeScoped_CouldBeModuleScoped0() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) => Invoke(new { x = 0 }, Target); + + static void Invoke(T t, Action f) => f(t); + + static void Target(T t) => Console.WriteLine(t); +} +"; + CompileAndVerify(source, expectedOutput: "{ x = 0 }").VerifyIL("C.Main", @" +{ + // Code size 39 (0x27) + .maxstack 3 + IL_0000: ldc.i4.0 + IL_0001: newobj ""<>f__AnonymousType0..ctor(int)"" + IL_0006: ldsfld ""System.Action<> C.<>O.<0>__Target"" + IL_000b: dup + IL_000c: brtrue.s IL_0021 + IL_000e: pop + IL_000f: ldnull + IL_0010: ldftn ""void C.Target<>()"" + IL_0016: newobj ""System.Action<>..ctor(object, System.IntPtr)"" + IL_001b: dup + IL_001c: stsfld ""System.Action<> C.<>O.<0>__Target"" + IL_0021: call ""void C.Invoke<>(, System.Action<>)"" + IL_0026: ret +} +"); + } + + [Fact] + public void AnonymousTypes_TypeScoped0() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) => (new D()).Test(0); +} +class D +{ + public void Test(G g) => Invoke(new { x = g }, Target); + + static void Invoke(T t, Action f) => f(t); + + static void Target(T t) => Console.WriteLine(t); +} +"; + CompileAndVerify(source, expectedOutput: "{ x = 0 }").VerifyIL("D.Test", @" +{ + // Code size 39 (0x27) + .maxstack 3 + IL_0000: ldarg.1 + IL_0001: newobj ""<>f__AnonymousType0..ctor(G)"" + IL_0006: ldsfld ""System.Action<> D.<>O.<0>__Target"" + IL_000b: dup + IL_000c: brtrue.s IL_0021 + IL_000e: pop + IL_000f: ldnull + IL_0010: ldftn ""void D.Target<>()"" + IL_0016: newobj ""System.Action<>..ctor(object, System.IntPtr)"" + IL_001b: dup + IL_001c: stsfld ""System.Action<> D.<>O.<0>__Target"" + IL_0021: call ""void D.Invoke<>(, System.Action<>)"" + IL_0026: ret +} +"); + } + + [Fact] + public void AnonymousTypes_TypeScoped1() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) => (new D()).Test(0); +} +class D +{ + public void Test(G g) => Invoke(new { x = g }, E.Target); + + static void Invoke(T t, Action f) => f(t); +} +class E +{ + public static void Target(T t) => Console.WriteLine(t); +} +"; + CompileAndVerify(source, expectedOutput: "{ x = 0 }").VerifyIL("D.Test", @" +{ + // Code size 39 (0x27) + .maxstack 3 + IL_0000: ldarg.1 + IL_0001: newobj ""<>f__AnonymousType0..ctor(G)"" + IL_0006: ldsfld ""System.Action<> D.<>O.<0>__Target"" + IL_000b: dup + IL_000c: brtrue.s IL_0021 + IL_000e: pop + IL_000f: ldnull + IL_0010: ldftn ""void E.Target<>()"" + IL_0016: newobj ""System.Action<>..ctor(object, System.IntPtr)"" + IL_001b: dup + IL_001c: stsfld ""System.Action<> D.<>O.<0>__Target"" + IL_0021: call ""void D.Invoke<>(, System.Action<>)"" + IL_0026: ret +} +"); + } + + [Fact] + public void AnonymousTypes_TypeScoped2() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) => D.Test(); +} +class D +{ + delegate void MyAction(T t); + + public static void Test() => Invoke(new { x = 0 }, Target); + + static void Invoke(T t, MyAction f) => f(t); + + static void Target(T t) => Console.WriteLine(t); +} +"; + CompileAndVerify(source, expectedOutput: "{ x = 0 }").VerifyIL("D.Test", @" +{ + // Code size 39 (0x27) + .maxstack 3 + IL_0000: ldc.i4.0 + IL_0001: newobj ""<>f__AnonymousType0..ctor(int)"" + IL_0006: ldsfld ""D.MyAction<> D.<>O.<0>__Target"" + IL_000b: dup + IL_000c: brtrue.s IL_0021 + IL_000e: pop + IL_000f: ldnull + IL_0010: ldftn ""void D.Target<>()"" + IL_0016: newobj ""D.MyAction<>..ctor(object, System.IntPtr)"" + IL_001b: dup + IL_001c: stsfld ""D.MyAction<> D.<>O.<0>__Target"" + IL_0021: call ""void D.Invoke<>(, D.MyAction<>)"" + IL_0026: ret +} +"); + } + + [Fact] + public void AnonymousTypes_MethodScoped0() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) => D.Test(0); +} +class D +{ + public static void Test(T t) => Invoke(new { x = t }, Target); + + static void Invoke(T t, Action f) => f(t); + + static void Target(T t) => Console.WriteLine(t); +} +"; + CompileAndVerify(source, expectedOutput: "{ x = 0 }").VerifyIL("D.Test", @" +{ + // Code size 39 (0x27) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: newobj ""<>f__AnonymousType0..ctor(T)"" + IL_0006: ldsfld ""System.Action<> D.O__0_0.<0>__Target"" + IL_000b: dup + IL_000c: brtrue.s IL_0021 + IL_000e: pop + IL_000f: ldnull + IL_0010: ldftn ""void D.Target<>()"" + IL_0016: newobj ""System.Action<>..ctor(object, System.IntPtr)"" + IL_001b: dup + IL_001c: stsfld ""System.Action<> D.O__0_0.<0>__Target"" + IL_0021: call ""void D.Invoke<>(, System.Action<>)"" + IL_0026: ret +} +"); + } + + [Fact] + public void AnonymousTypes_MethodScoped1() + { + var source = @" +using System; +class C +{ + static void Main(string[] args) => D.Test(0); +} +class D +{ + public static void Test(T t) => Invoke(t, new { x = 0 }, Target); + + static void Invoke(T t, V v, Action f) => f(t, v); + + static void Target(T t, V v) => Console.WriteLine(v); +} +"; + CompileAndVerify(source, expectedOutput: "{ x = 0 }").VerifyIL("D.Test", @" +{ + // Code size 40 (0x28) + .maxstack 4 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: newobj ""<>f__AnonymousType0..ctor(int)"" + IL_0007: ldsfld ""System.Action> D.O__0_0.<0>__Target"" + IL_000c: dup + IL_000d: brtrue.s IL_0022 + IL_000f: pop + IL_0010: ldnull + IL_0011: ldftn ""void D.Target>(T, )"" + IL_0017: newobj ""System.Action>..ctor(object, System.IntPtr)"" + IL_001c: dup + IL_001d: stsfld ""System.Action> D.O__0_0.<0>__Target"" + IL_0022: call ""void D.Invoke>(T, , System.Action>)"" + IL_0027: ret +} +"); + } + + [Fact] + public void AnonymousClass_AnonymousDelegate0() + { + var source = @" +using System; +class D +{ + public void Owner() + { + static void Test(T t) + { + var f = F; + var a = new { x = f }; + + Invoke(a, Target); + } + } + + static void F(ref T t) { } + + static void Invoke(T t, Action f) { } + + static void Target(T t) { } +} +"; + CompileAndVerify(source).VerifyIL("D.g__Test|0_0", @" +{ + // Code size 65 (0x41) + .maxstack 3 + IL_0000: ldsfld "" D.O__0_0.<0>__F"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void D.F(ref T)"" + IL_0010: newobj ""<>A{00000001}..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld "" D.O__0_0.<0>__F"" + IL_001b: newobj ""<>f__AnonymousType0<>..ctor()"" + IL_0020: ldsfld ""System.Action< x>> D.O__0_0.<1>__Target"" + IL_0025: dup + IL_0026: brtrue.s IL_003b + IL_0028: pop + IL_0029: ldnull + IL_002a: ldftn ""void D.Target< x>>( x>)"" + IL_0030: newobj ""System.Action< x>>..ctor(object, System.IntPtr)"" + IL_0035: dup + IL_0036: stsfld ""System.Action< x>> D.O__0_0.<1>__Target"" + IL_003b: call ""void D.Invoke< x>>( x>, System.Action< x>>)"" + IL_0040: ret +} +"); + } + + [Fact] + public void AnonymousClass_AnonymousDelegate1() + { + var source = @" +using System; +class D +{ + public void Top() + { + static void Test(T t) + { + var f = F; + var a = new { x = f }; + + Invoke(a, Target); + } + } + + static void F(ref T t) { } + + static void Invoke(G t, Action f) { } + + static void Target(G t) { } +} +"; + CompileAndVerify(source).VerifyIL("D.g__Test|0_0", @" +{ + // Code size 65 (0x41) + .maxstack 3 + IL_0000: ldsfld "" D.<>O.<0>__F"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void D.F(ref T)"" + IL_0010: newobj ""<>A{00000001}..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld "" D.<>O.<0>__F"" + IL_001b: newobj ""<>f__AnonymousType0<>..ctor()"" + IL_0020: ldsfld ""System.Action< x>> D.<>O.<1>__Target"" + IL_0025: dup + IL_0026: brtrue.s IL_003b + IL_0028: pop + IL_0029: ldnull + IL_002a: ldftn ""void D.Target< x>>( x>)"" + IL_0030: newobj ""System.Action< x>>..ctor(object, System.IntPtr)"" + IL_0035: dup + IL_0036: stsfld ""System.Action< x>> D.<>O.<1>__Target"" + IL_003b: call ""void D.Invoke< x>>( x>, System.Action< x>>)"" + IL_0040: ret +} +"); + } + + [Fact] + public void Pointer_TypeScoped_CouldBeModuleScoped0() + { + var source = @" +using System; +class C +{ + unsafe void Test() + { + Func t = Target; + t(); + } + + unsafe static int*[] Target() => default(int*[]); +} +"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseDll).VerifyIL("C.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int*[] C.Target()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.<>O.<0>__Target"" + IL_001b: callvirt ""int*[] System.Func.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void Pointer_TypeScoped0() + { + var source = @" +using System; +class C +{ + unsafe void Test() + { + Func t = Target; + t(default(T)); + } + + unsafe static int*[] Target(T t) => default(int*[]); +} +"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseDll).VerifyIL("C.Test", @" +{ + // Code size 43 (0x2b) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldsfld ""System.Func C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int*[] C.Target(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.<>O.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""T"" + IL_0023: ldloc.0 + IL_0024: callvirt ""int*[] System.Func.Invoke(T)"" + IL_0029: pop + IL_002a: ret +} +"); + } + + [Fact] + public void Pointer_MethodScoped0() + { + var source = @" +using System; +class C +{ + unsafe void Test(T t) + { + Func f = Target; + f(t); + } + + unsafe static int*[] Target(G g) => default(int*[]); +} +"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseDll).VerifyIL("C.Test", @" +{ + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""int*[] C.Target(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_001b: ldarg.1 + IL_001c: callvirt ""int*[] System.Func.Invoke(T)"" + IL_0021: pop + IL_0022: ret +} +"); + } + + [Fact] + public void Dynamic_TypeScoped_CouldBeModuleScoped0() + { + var source = @" +using System; +class C +{ + void Test() + { + Func t = Target; + t(); + } + + static dynamic Target() => 0; +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 34 (0x22) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic C.Target()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.<>O.<0>__Target"" + IL_001b: callvirt ""dynamic System.Func.Invoke()"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Fact] + public void Dynamic_TypeScoped0() + { + var source = @" +using System; +class C +{ + void Test() + { + Func t = Target; + t(default(T)); + } + + static dynamic Target(T t) => 0; +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 43 (0x2b) + .maxstack 2 + .locals init (T V_0) + IL_0000: ldsfld ""System.Func C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic C.Target(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.<>O.<0>__Target"" + IL_001b: ldloca.s V_0 + IL_001d: initobj ""T"" + IL_0023: ldloc.0 + IL_0024: callvirt ""dynamic System.Func.Invoke(T)"" + IL_0029: pop + IL_002a: ret +} +"); + } + + [Fact] + public void Dynamic_MethodScoped0() + { + var source = @" +using System; +class C +{ + void Test(T t) + { + Func f = Target; + f(t); + } + + static dynamic Target(G g) => 0; +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic C.Target(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_001b: ldarg.1 + IL_001c: callvirt ""dynamic System.Func.Invoke(T)"" + IL_0021: pop + IL_0022: ret +} +"); + } + + [Fact] + public void SynthesizedAnonymousDelegate_TypeScoped0() + { + var source = @" +using System; +class C +{ + void Test(T t) + { + G(Target); + } + + void G(Delegate d) {} + + static dynamic Target(ref G g) => 0; +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 34 (0x22) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldsfld "" C.<>O.<0>__Target"" + IL_0006: dup + IL_0007: brtrue.s IL_001c + IL_0009: pop + IL_000a: ldnull + IL_000b: ldftn ""dynamic C.Target(ref int)"" + IL_0011: newobj ""<>F{00000001}..ctor(object, System.IntPtr)"" + IL_0016: dup + IL_0017: stsfld "" C.<>O.<0>__Target"" + IL_001c: call ""void C.G(System.Delegate)"" + IL_0021: ret +} +"); + } + + [Fact] + public void SynthesizedAnonymousDelegate_MethodScoped0() + { + var source = @" +using System; +class C +{ + void Test(T t) + { + G(Target); + } + + void G(Delegate d) {} + + static dynamic Target(ref G g) => 0; +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 34 (0x22) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldsfld "" C.O__0_0.<0>__Target"" + IL_0006: dup + IL_0007: brtrue.s IL_001c + IL_0009: pop + IL_000a: ldnull + IL_000b: ldftn ""dynamic C.Target(ref T)"" + IL_0011: newobj ""<>F{00000001}..ctor(object, System.IntPtr)"" + IL_0016: dup + IL_0017: stsfld "" C.O__0_0.<0>__Target"" + IL_001c: call ""void C.G(System.Delegate)"" + IL_0021: ret +} +"); + } + + [Fact] + public void TopLevelMethod_LocalFunctions_TypeScoped0() + { + var source = @" +using System; +class C +{ + void Test(int t) + { + Func f = Target; + f(t); + + static dynamic Target(G g) => 0; + } +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic C.g__Target|0_0(int)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.<>O.<0>__Target"" + IL_001b: ldarg.1 + IL_001c: callvirt ""dynamic System.Func.Invoke(int)"" + IL_0021: pop + IL_0022: ret +} +"); + } + + [Fact] + public void TopLevelMethod_LocalFunctions_NotStatic() + { + var source = @" +using System; +class C +{ + void Test(int t) + { + Func f = Target; + f(t); + + dynamic Target(G g) => 0; + } +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 20 (0x14) + .maxstack 2 + IL_0000: ldnull + IL_0001: ldftn ""dynamic C.g__Target|0_0(int)"" + IL_0007: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_000c: ldarg.1 + IL_000d: callvirt ""dynamic System.Func.Invoke(int)"" + IL_0012: pop + IL_0013: ret +} +"); + } + + [Fact] + public void TopLevelMethod_LocalFunctions_MethodScoped0() + { + var source = @" +using System; +class C +{ + void Test(T t) + { + Func f = Target; + f(t); + + static dynamic Target(G g) => 0; + } +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic C.g__Target|0_0(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_001b: ldarg.1 + IL_001c: callvirt ""dynamic System.Func.Invoke(T)"" + IL_0021: pop + IL_0022: ret +} +"); + } + + [Fact] + public void Local_LocalFunctions_MethodScoped0() + { + var source = @" +using System; +class C +{ + void TopLevel(T t) + { + void Test() + { + Func f = Target; + f(t); + + static dynamic Target(G g) => 0; + } + } +} +"; + CompileAndVerify(source).VerifyIL("C.g__Test|0_0", @" +{ + // Code size 40 (0x28) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic C.g__Target|0_1(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_001b: ldarg.0 + IL_001c: ldfld ""T C.<>c__DisplayClass0_0.t"" + IL_0021: callvirt ""dynamic System.Func.Invoke(T)"" + IL_0026: pop + IL_0027: ret +} +"); + } + + [Fact] + public void Lambda_Local_LocalFunctions_MethodScoped0() + { + var source = @" +using System; +class C +{ + void TopLevel(T t) + { + Action x = () => + { + void Test() + { + Func f = Target; + f(t); + + static dynamic Target(G g) => 0; + } + + Test(); + }; + + x(); + } +} +"; + CompileAndVerify(source).VerifyIL("C.<>c__DisplayClass0_0.g__Test|1", @" +{ + // Code size 40 (0x28) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic C.g__Target|0_2(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_001b: ldarg.0 + IL_001c: ldfld ""T C.<>c__DisplayClass0_0.t"" + IL_0021: callvirt ""dynamic System.Func.Invoke(T)"" + IL_0026: pop + IL_0027: ret +} +"); + } + + [Fact] + public void Lambda_Local_LocalFunctions_MethodScoped1() + { + var source = @" +using System; +class C +{ + void TopLevel(T t) + { + Action y = () => + { + void Test() { /* Test method ordinals in generated names */ } + Test(); + }; + Action x = () => + { + void Test() + { + Func f = Target; + f(t); + + static dynamic Target(G g) => 0; + } + + Test(); + }; + + x(); + y(); + } +} +"; + CompileAndVerify(source).VerifyIL("C.<>c__DisplayClass0_0.g__Test|3", @" +{ + // Code size 40 (0x28) + .maxstack 2 + IL_0000: ldsfld ""System.Func C.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic C.g__Target|0_4(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func C.O__0_0.<0>__Target"" + IL_001b: ldarg.0 + IL_001c: ldfld ""T C.<>c__DisplayClass0_0.t"" + IL_0021: callvirt ""dynamic System.Func.Invoke(T)"" + IL_0026: pop + IL_0027: ret +} +"); + } + + [Fact] + public void TopLevelStatement_Lambda_Local_LocalFunctions_MethodScoped0() + { + var source = @" +using System; + +Action y = () => +{ + void Test() { /* Test method ordinals in generated names */ } + Test(); +}; +Action x = () => +{ + void Test(T t) + { + Func f = Target; + f(t); + + static dynamic Target(G g) => 0; + } + + Test(0); +}; + +x(); +y(); +"; + CompileAndVerify(source).VerifyIL("Program.<
$>g__Test|0_3", @" +{ + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldsfld ""System.Func Program.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic Program.<
$>g__Target|0_4(T)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func Program.O__0_0.<0>__Target"" + IL_001b: ldarg.0 + IL_001c: callvirt ""dynamic System.Func.Invoke(T)"" + IL_0021: pop + IL_0022: ret +} +"); + } + + [Fact] + public void TopLevelStatement_Lambda_Local_LocalFunctions_MethodScoped1() + { + var source = @" +var y = () => +{ + void Test() { /* Test method ordinals in generated names */ } + Test(); +}; +var x = () => +{ + void Test(T t) + { + var f = Target; + f(0); + + static dynamic Target(G g) + { + T f = default; + return f; + } + } + + Test(false); +}; + +x(); +y(); +"; + CompileAndVerify(source).VerifyIL("Program.<
$>g__Test|0_3", @" +{ + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldsfld ""System.Func Program.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""dynamic Program.<
$>g__Target|0_4(int)"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func Program.O__0_0.<0>__Target"" + IL_001b: ldc.i4.0 + IL_001c: callvirt ""dynamic System.Func.Invoke(int)"" + IL_0021: pop + IL_0022: ret +} +"); + } + + [Fact] + public void TopLevelStatement_Tuples_LocalFunction_TypeScoped0() + { + var source = @" +(System.Action a, int _) = (Target, 0); +static void Target() { } +"; + CompileAndVerify(source).VerifyIL("", @" +{ + // Code size 29 (0x1d) + .maxstack 2 + IL_0000: ldsfld ""System.Action Program.<>O.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void Program.<
$>g__Target|0_0()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action Program.<>O.<0>__Target"" + IL_001b: pop + IL_001c: ret +} +"); + } + + [Fact] + public void TopLevelStatement_Tuples_LocalFunction_TypeScoped1() + { + var source = @" +var t = Target; +static (int a, int b) Target() => (0, 0); +"; + CompileAndVerify(source).VerifyIL("", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func> Program.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""System.ValueTuple Program.<
$>g__Target|0_0()"" + IL_000e: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func> Program.<>O.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void TopLevelStatement_Tuples_LocalFunction_MethodScoped0() + { + var source = @" +Test(0); +static void Test(T t) +{ + (System.Action a, int _) = (Target, 0); + static void Target() { } +} +"; + CompileAndVerify(source).VerifyIL("Program.<
$>g__Test|0_0", @" +{ + // Code size 29 (0x1d) + .maxstack 2 + IL_0000: ldsfld ""System.Action Program.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void Program.<
$>g__Target|0_1()"" + IL_0010: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Action Program.O__0_0.<0>__Target"" + IL_001b: pop + IL_001c: ret +} +"); + } + + [Fact] + public void TopLevelStatement_Tuples_LocalFunction_MethodScoped1() + { + var source = @" +Test(0); +static void Test(T t) +{ + (System.Func<(T, int)> a, int _) = (Target, 0); + static (T, int) Target() => (default(T), 0); +} +"; + CompileAndVerify(source).VerifyIL("Program.<
$>g__Test|0_0", @" +{ + // Code size 29 (0x1d) + .maxstack 2 + IL_0000: ldsfld ""System.Func> Program.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""System.ValueTuple Program.<
$>g__Target|0_1()"" + IL_0010: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func> Program.O__0_0.<0>__Target"" + IL_001b: pop + IL_001c: ret +} +"); + } + + [Fact] + public void TopLevelStatement_Tuples_LocalFunction_MethodScoped2() + { + var source = @" +Test(0); +static void Test(T t) +{ + (System.Func a, int _) = (Target, 0); + static (T, G) Target(G g) => (default(T), g); +} +"; + CompileAndVerify(source).VerifyIL("Program.<
$>g__Test|0_0", @" +{ + // Code size 29 (0x1d) + .maxstack 2 + IL_0000: ldsfld ""System.Func> Program.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""System.ValueTuple Program.<
$>g__Target|0_1(T)"" + IL_0010: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func> Program.O__0_0.<0>__Target"" + IL_001b: pop + IL_001c: ret +} +"); + } + + [Fact] + public void TopLevelStatement_Tuples_LocalFunction_MethodScoped3() + { + var source = @" +Test(0); +static void Test(T t) +{ + (System.Func a, int _) = (Target, 0); +} +static (T, G) Target(G g) => (default(T), g); +"; + CompileAndVerify(source).VerifyIL("Program.<
$>g__Test|0_0", @" +{ + // Code size 29 (0x1d) + .maxstack 2 + IL_0000: ldsfld ""System.Func> Program.O__0_0.<0>__Target"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""System.ValueTuple Program.<
$>g__Target|0_1(T)"" + IL_0010: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func> Program.O__0_0.<0>__Target"" + IL_001b: pop + IL_001c: ret +} +"); + } + + [Fact] + public void Tuples_LocalFunction_TypeScoped0() + { + var source = @" +class C +{ + void Test() + { + var x = Target; + static (T, T) Target(T t) => (t, t); + } +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func> C.<>O.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""System.ValueTuple C.g__Target|0_0(T)"" + IL_000e: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func> C.<>O.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void Tuples_LocalFunction_MethodScoped0() + { + var source = @" +class C +{ + void Test() + { + var x = Target; + static (T, G) Target(T t, G g) => (t, g); + } +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func> C.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""System.ValueTuple C.g__Target|0_0(T, G)"" + IL_000e: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func> C.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void Tuples_LocalFunction_MethodScoped1() + { + var source = @" +class C +{ + void Test() + { + var x = Target; + static (T, G, V) Target(T t, G g, V v) => (t, g, v); + } +} +"; + CompileAndVerify(source).VerifyIL("C.Test", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func> C.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""System.ValueTuple C.g__Target|0_0(T, G, T)"" + IL_000e: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func> C.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void Tuples_LocalFunction_MethodScoped2() + { + var source = @" +class M +{ + void F() + { + void Test() + { + var x = Target; + static (N, I, C, E) Target(N n, I i, C c, E e) => (n, i, c, e); + } + } +} +"; + CompileAndVerify(source).VerifyIL("M.g__Test|0_0", @" +{ + // Code size 25 (0x19) + .maxstack 2 + IL_0000: ldsfld ""System.Func> M.O__0_0.<0>__Target"" + IL_0005: brtrue.s IL_0018 + IL_0007: ldnull + IL_0008: ldftn ""System.ValueTuple M.g__Target|0_1(N, I, C, N)"" + IL_000e: newobj ""System.Func>..ctor(object, System.IntPtr)"" + IL_0013: stsfld ""System.Func> M.O__0_0.<0>__Target"" + IL_0018: ret +} +"); + } + + [Fact] + public void TestConditionalOperatorMethodGroup() + { + var source = @" +class C +{ + static void Main() + { + bool b = true; + System.Func f = null; + System.Console.WriteLine(f); + System.Func g1 = b ? f : M; + System.Console.WriteLine(g1); + System.Func g2 = b ? M : f; + System.Console.WriteLine(g2); + } + + static int M() + { + return 0; + } +}"; + var comp = CompileAndVerify(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + comp.VerifyIL("C.Main", @" +{ + // Code size 85 (0x55) + .maxstack 3 + .locals init (System.Func V_0) //f + IL_0000: ldc.i4.1 + IL_0001: ldnull + IL_0002: stloc.0 + IL_0003: ldloc.0 + IL_0004: call ""void System.Console.WriteLine(object)"" + IL_0009: dup + IL_000a: brtrue.s IL_0029 + IL_000c: ldsfld ""System.Func C.<>O.<0>__M"" + IL_0011: dup + IL_0012: brtrue.s IL_002a + IL_0014: pop + IL_0015: ldnull + IL_0016: ldftn ""int C.M()"" + IL_001c: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0021: dup + IL_0022: stsfld ""System.Func C.<>O.<0>__M"" + IL_0027: br.s IL_002a + IL_0029: ldloc.0 + IL_002a: call ""void System.Console.WriteLine(object)"" + IL_002f: brtrue.s IL_0034 + IL_0031: ldloc.0 + IL_0032: br.s IL_004f + IL_0034: ldsfld ""System.Func C.<>O.<0>__M"" + IL_0039: dup + IL_003a: brtrue.s IL_004f + IL_003c: pop + IL_003d: ldnull + IL_003e: ldftn ""int C.M()"" + IL_0044: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0049: dup + IL_004a: stsfld ""System.Func C.<>O.<0>__M"" + IL_004f: call ""void System.Console.WriteLine(object)"" + IL_0054: ret +} +"); + } + + [Fact] + public void WinMdEventAssignment() + { + var source = @" +class C +{ + public event System.Action Instance; + public static event System.Action Static; +} + +class D +{ + C c; + + void InstanceAdd() + { + c.Instance += Action; + } + + void InstanceRemove() + { + c.Instance -= Action; + } + + static void StaticAdd() + { + C.Static += Action; + } + + static void StaticRemove() + { + C.Static -= Action; + } + + static void Action() + { + } +} +"; + var verifier = CompileAndVerifyWithWinRt(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseWinMD); + + verifier.VerifyIL("D.InstanceAdd", @" +{ + // Code size 64 (0x40) + .maxstack 4 + .locals init (C V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""C D.c"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldftn ""System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken C.Instance.add"" + IL_000e: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0013: ldloc.0 + IL_0014: ldftn ""void C.Instance.remove"" + IL_001a: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_001f: ldsfld ""System.Action D.<>O.<0>__Action"" + IL_0024: dup + IL_0025: brtrue.s IL_003a + IL_0027: pop + IL_0028: ldnull + IL_0029: ldftn ""void D.Action()"" + IL_002f: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0034: dup + IL_0035: stsfld ""System.Action D.<>O.<0>__Action"" + IL_003a: call ""void System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.AddEventHandler(System.Func, System.Action, System.Action)"" + IL_003f: ret +}"); + + verifier.VerifyIL("D.InstanceRemove", @" +{ + // Code size 50 (0x32) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldfld ""C D.c"" + IL_0006: ldftn ""void C.Instance.remove"" + IL_000c: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0011: ldsfld ""System.Action D.<>O.<0>__Action"" + IL_0016: dup + IL_0017: brtrue.s IL_002c + IL_0019: pop + IL_001a: ldnull + IL_001b: ldftn ""void D.Action()"" + IL_0021: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0026: dup + IL_0027: stsfld ""System.Action D.<>O.<0>__Action"" + IL_002c: call ""void System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.RemoveEventHandler(System.Action, System.Action)"" + IL_0031: ret +}"); + verifier.VerifyIL("D.StaticAdd", @" +{ + // Code size 57 (0x39) + .maxstack 4 + IL_0000: ldnull + IL_0001: ldftn ""System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken C.Static.add"" + IL_0007: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_000c: ldnull + IL_000d: ldftn ""void C.Static.remove"" + IL_0013: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0018: ldsfld ""System.Action D.<>O.<0>__Action"" + IL_001d: dup + IL_001e: brtrue.s IL_0033 + IL_0020: pop + IL_0021: ldnull + IL_0022: ldftn ""void D.Action()"" + IL_0028: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_002d: dup + IL_002e: stsfld ""System.Action D.<>O.<0>__Action"" + IL_0033: call ""void System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.AddEventHandler(System.Func, System.Action, System.Action)"" + IL_0038: ret +}"); + + verifier.VerifyIL("D.StaticRemove", @" +{ + // Code size 45 (0x2d) + .maxstack 3 + IL_0000: ldnull + IL_0001: ldftn ""void C.Static.remove"" + IL_0007: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_000c: ldsfld ""System.Action D.<>O.<0>__Action"" + IL_0011: dup + IL_0012: brtrue.s IL_0027 + IL_0014: pop + IL_0015: ldnull + IL_0016: ldftn ""void D.Action()"" + IL_001c: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0021: dup + IL_0022: stsfld ""System.Action D.<>O.<0>__Action"" + IL_0027: call ""void System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.RemoveEventHandler(System.Action, System.Action)"" + IL_002c: ret +}"); + } + + [Fact] + public void WinMdEventFieldAssignment() + { + var source = @" +class C +{ + public event System.Action Instance; + public static event System.Action Static; + + void InstanceAssign() + { + Instance = Action; + } + + static void StaticAssign() + { + Static = Action; + } + + static void Action() + { + } +} +"; + var verifier = CompileAndVerifyWithWinRt(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseWinMD); + + verifier.VerifyIL("C.InstanceAssign", @" +{ + // Code size 74 (0x4a) + .maxstack 4 + IL_0000: ldarg.0 + IL_0001: ldftn ""void C.Instance.remove"" + IL_0007: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_000c: call ""void System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.RemoveAllEventHandlers(System.Action)"" + IL_0011: ldarg.0 + IL_0012: ldftn ""System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken C.Instance.add"" + IL_0018: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_001d: ldarg.0 + IL_001e: ldftn ""void C.Instance.remove"" + IL_0024: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0029: ldsfld ""System.Action C.<>O.<0>__Action"" + IL_002e: dup + IL_002f: brtrue.s IL_0044 + IL_0031: pop + IL_0032: ldnull + IL_0033: ldftn ""void C.Action()"" + IL_0039: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_003e: dup + IL_003f: stsfld ""System.Action C.<>O.<0>__Action"" + IL_0044: call ""void System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.AddEventHandler(System.Func, System.Action, System.Action)"" + IL_0049: ret +}"); + + verifier.VerifyIL("C.StaticAssign", @" +{ + // Code size 74 (0x4a) + .maxstack 4 + IL_0000: ldnull + IL_0001: ldftn ""void C.Static.remove"" + IL_0007: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_000c: call ""void System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.RemoveAllEventHandlers(System.Action)"" + IL_0011: ldnull + IL_0012: ldftn ""System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken C.Static.add"" + IL_0018: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_001d: ldnull + IL_001e: ldftn ""void C.Static.remove"" + IL_0024: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0029: ldsfld ""System.Action C.<>O.<0>__Action"" + IL_002e: dup + IL_002f: brtrue.s IL_0044 + IL_0031: pop + IL_0032: ldnull + IL_0033: ldftn ""void C.Action()"" + IL_0039: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_003e: dup + IL_003f: stsfld ""System.Action C.<>O.<0>__Action"" + IL_0044: call ""void System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.AddEventHandler(System.Func, System.Action, System.Action)"" + IL_0049: ret +}"); + } + + [Fact] + public void LockDelegate() + { + var text = +@" +delegate void D(string p1); +partial class Test +{ + public static void Main() + { + D d1; + lock (d1 = PM) + { + d1(""PASS""); + } + } + static partial void PM(string p2); + static partial void PM(string p2) + { + System.Console.WriteLine(p2); + } +} +"; + + CompileAndVerify(text, parseOptions: TestOptions.RegularNext, expectedOutput: PASS).VerifyIL("Test.Main", @" +{ + // Code size 64 (0x40) + .maxstack 2 + .locals init (D V_0, //d1 + D V_1, + bool V_2) + IL_0000: ldsfld ""D Test.<>O.<0>__PM"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""void Test.PM(string)"" + IL_0010: newobj ""D..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""D Test.<>O.<0>__PM"" + IL_001b: dup + IL_001c: stloc.0 + IL_001d: stloc.1 + IL_001e: ldc.i4.0 + IL_001f: stloc.2 + .try + { + IL_0020: ldloc.1 + IL_0021: ldloca.s V_2 + IL_0023: call ""void System.Threading.Monitor.Enter(object, ref bool)"" + IL_0028: ldloc.0 + IL_0029: ldstr ""PASS"" + IL_002e: callvirt ""void D.Invoke(string)"" + IL_0033: leave.s IL_003f + } + finally + { + IL_0035: ldloc.2 + IL_0036: brfalse.s IL_003e + IL_0038: ldloc.1 + IL_0039: call ""void System.Threading.Monitor.Exit(object)"" + IL_003e: endfinally + } + IL_003f: ret +} +"); + } + + [Fact] + public void NullCoalescingAssignmentValidRHS() + { + CompileAndVerify(@" +using System; +public class C +{ + public static void Main() + { + Action a = null; + (a ??= TestMethod)(); + (a ??= () => {})(); + } + static void TestMethod() => Console.WriteLine(""In TestMethod""); +} +", parseOptions: TestOptions.RegularNext, expectedOutput: @" +In TestMethod +In TestMethod +").VerifyIL("C.Main()", @" +{ + // Code size 85 (0x55) + .maxstack 2 + .locals init (System.Action V_0) //a + IL_0000: ldnull + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: dup + IL_0004: brtrue.s IL_0024 + IL_0006: pop + IL_0007: ldsfld ""System.Action C.<>O.<0>__TestMethod"" + IL_000c: dup + IL_000d: brtrue.s IL_0022 + IL_000f: pop + IL_0010: ldnull + IL_0011: ldftn ""void C.TestMethod()"" + IL_0017: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_001c: dup + IL_001d: stsfld ""System.Action C.<>O.<0>__TestMethod"" + IL_0022: dup + IL_0023: stloc.0 + IL_0024: callvirt ""void System.Action.Invoke()"" + IL_0029: ldloc.0 + IL_002a: dup + IL_002b: brtrue.s IL_004f + IL_002d: pop + IL_002e: ldsfld ""System.Action C.<>c.<>9__0_0"" + IL_0033: dup + IL_0034: brtrue.s IL_004d + IL_0036: pop + IL_0037: ldsfld ""C.<>c C.<>c.<>9"" + IL_003c: ldftn ""void C.<>c.
b__0_0()"" + IL_0042: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0047: dup + IL_0048: stsfld ""System.Action C.<>c.<>9__0_0"" + IL_004d: dup + IL_004e: stloc.0 + IL_004f: callvirt ""void System.Action.Invoke()"" + IL_0054: ret +}"); + } + + [Fact] + public void ImplicitlyTypedVariables_01() + { + var source = +@"using System; +class Program +{ + static void Main() + { + var d1 = Main; + Report(d1); + var d2 = () => { }; + Report(d2); + var d3 = delegate () { }; + Report(d3); + } + static void Report(Delegate d) => Console.WriteLine($""{d.GetType().Namespace}.{d.GetType().Name}""); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + + var verifier = CompileAndVerify(comp, expectedOutput: +@"System.Action +System.Action +System.Action"); + verifier.VerifyIL("Program.Main", @" +{ + // Code size 115 (0x73) + .maxstack 2 + .locals init (System.Action V_0, //d1 + System.Action V_1, //d2 + System.Action V_2) //d3 + IL_0000: nop + IL_0001: ldsfld ""System.Action Program.<>O.<0>__Main"" + IL_0006: dup + IL_0007: brtrue.s IL_001c + IL_0009: pop + IL_000a: ldnull + IL_000b: ldftn ""void Program.Main()"" + IL_0011: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0016: dup + IL_0017: stsfld ""System.Action Program.<>O.<0>__Main"" + IL_001c: stloc.0 + IL_001d: ldloc.0 + IL_001e: call ""void Program.Report(System.Delegate)"" + IL_0023: nop + IL_0024: ldsfld ""System.Action Program.<>c.<>9__0_0"" + IL_0029: dup + IL_002a: brtrue.s IL_0043 + IL_002c: pop + IL_002d: ldsfld ""Program.<>c Program.<>c.<>9"" + IL_0032: ldftn ""void Program.<>c.
b__0_0()"" + IL_0038: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_003d: dup + IL_003e: stsfld ""System.Action Program.<>c.<>9__0_0"" + IL_0043: stloc.1 + IL_0044: ldloc.1 + IL_0045: call ""void Program.Report(System.Delegate)"" + IL_004a: nop + IL_004b: ldsfld ""System.Action Program.<>c.<>9__0_1"" + IL_0050: dup + IL_0051: brtrue.s IL_006a + IL_0053: pop + IL_0054: ldsfld ""Program.<>c Program.<>c.<>9"" + IL_0059: ldftn ""void Program.<>c.
b__0_1()"" + IL_005f: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0064: dup + IL_0065: stsfld ""System.Action Program.<>c.<>9__0_1"" + IL_006a: stloc.2 + IL_006b: ldloc.2 + IL_006c: call ""void Program.Report(System.Delegate)"" + IL_0071: nop + IL_0072: ret +} +"); + } + + [Fact] + public void CustomModifiers_Method() + { + var ilSource = @" +.class public auto ansi beforefieldinit C1`1 + extends System.Object +{ + // Methods + .method public hidebysig static + string Method () cil managed + { + // Method begins at RVA 0x2050 + // Code size 6 (0x6) + .maxstack 8 + + IL_0000: ldstr ""PASS"" + IL_0005: ret + } // end of method C1`1::Method + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2057 + // Code size 7 (0x7) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void System.Object::.ctor() + IL_0006: ret + } // end of method C1`1::.ctor + +} // end of class C1`1 + +.class public auto ansi beforefieldinit C2`1 + extends System.Object +{ + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2057 + // Code size 7 (0x7) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void System.Object::.ctor() + IL_0006: ret + } // end of method C2`1::.ctor + +} // end of class C2`1 + +.class public auto ansi beforefieldinit C3`1 + extends class C1`1)> +{ + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x205f + // Code size 7 (0x7) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void class C1`1::.ctor() + IL_0006: ret + } // end of method C3`1::.ctor + +} // end of class C3`1 +"; + var source = @" +class Test +{ + static void Main() + { + M(); + } + + static void M() + { + System.Func x = C3.Method; + System.Console.WriteLine(x()); + } +} +"; + var compilation = CreateCompilationWithIL(source, ilSource, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(compilation, expectedOutput: PASS); + verifier.VerifyIL("Test.M", @" +{ + // Code size 38 (0x26) + .maxstack 2 + IL_0000: ldsfld ""System.Func Test.O__1_0.<0>__Method"" + IL_0005: dup + IL_0006: brtrue.s IL_001b + IL_0008: pop + IL_0009: ldnull + IL_000a: ldftn ""string C1.Method()"" + IL_0010: newobj ""System.Func..ctor(object, System.IntPtr)"" + IL_0015: dup + IL_0016: stsfld ""System.Func Test.O__1_0.<0>__Method"" + IL_001b: callvirt ""string System.Func.Invoke()"" + IL_0020: call ""void System.Console.WriteLine(string)"" + IL_0025: ret +} +"); + } + + [Fact] + public void CustomModifiers_Delegate() + { + var ilSource = @" +.class public auto ansi beforefieldinit C1`1 + extends [mscorlib]System.Object +{ + // Nested Types + .class nested public auto ansi sealed F + extends [mscorlib]System.MulticastDelegate + { + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method F::.ctor + + .method public hidebysig newslot virtual + instance string Invoke () runtime managed + { + } // end of method F::Invoke + + .method public hidebysig newslot virtual + instance class [mscorlib]System.IAsyncResult BeginInvoke ( + class [mscorlib]System.AsyncCallback callback, + object 'object' + ) runtime managed + { + } // end of method F::BeginInvoke + + .method public hidebysig newslot virtual + instance string EndInvoke ( + class [mscorlib]System.IAsyncResult result + ) runtime managed + { + } // end of method F::EndInvoke + + } // end of class F + + + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x211f + // Code size 8 (0x8) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method C1`1::.ctor + +} // end of class C1`1 + +.class public auto ansi beforefieldinit C2`1 + extends System.Object +{ + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2057 + // Code size 7 (0x7) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void System.Object::.ctor() + IL_0006: ret + } // end of method C2`1::.ctor + +} // end of class C2`1 + +.class public auto ansi beforefieldinit C3`1 + extends class C1`1)> +{ + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x205f + // Code size 7 (0x7) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void class C1`1::.ctor() + IL_0006: ret + } // end of method C3`1::.ctor + +} // end of class C3`1 +"; + var source = @" +class Test +{ + static void Main() + { + M(); + } + + static void M() + { + C3.F x = Method; + System.Console.WriteLine(x()); + } + + static string Method() => ""PASS""; +} +"; + static void containerValidator(ModuleSymbol module) + { + var container = module.GlobalNamespace.GetMember("Test.O__1_0"); + var field = Assert.Single(container.GetMembers()) as FieldSymbol; + AssertEx.NotNull(field); + + var typeParameters = new List(); + field.Type.VisitType(static (typeSymbol, typeParameters, _) => + { + if (typeSymbol is TypeParameterSymbol typeParameter) + { + typeParameters.Add(typeParameter); + } + + return false; + }, + typeParameters, visitCustomModifiers: true); + + var typeParameter = Assert.Single(typeParameters); + Assert.Equal("G", typeParameter.Name); + Assert.Equal("O__1_0", typeParameter.ContainingSymbol.Name); + } + var compilation = CreateCompilationWithIL(source, ilSource, options: TestOptions.DebugExe); + var verifier = CompileAndVerify(compilation, expectedOutput: PASS, symbolValidator: containerValidator); + verifier.VerifyIL("Test.M", @" +{ + // Code size 42 (0x2a) + .maxstack 2 + .locals init (C1.F V_0) //x + IL_0000: nop + IL_0001: ldsfld ""C1.F Test.O__1_0.<0>__Method"" + IL_0006: dup + IL_0007: brtrue.s IL_001c + IL_0009: pop + IL_000a: ldnull + IL_000b: ldftn ""string Test.Method()"" + IL_0011: newobj ""C1.F..ctor(object, System.IntPtr)"" + IL_0016: dup + IL_0017: stsfld ""C1.F Test.O__1_0.<0>__Method"" + IL_001c: stloc.0 + IL_001d: ldloc.0 + IL_001e: callvirt ""string C1.F.Invoke()"" + IL_0023: call ""void System.Console.WriteLine(string)"" + IL_0028: nop + IL_0029: ret +} +"); + } + + private static Action VerifyCacheContainer(string typeName, int arity, params string[] expectedFields) + { + return module => + { + var container = module.GlobalNamespace.GetMember(typeName); + AssertEx.NotNull(container); + Assert.Equal(arity, container.Arity); + + var fields = container.GetMembers().OfType().Select(field => $"{field.Type.ToTestDisplayString()} {field.Name}").ToArray(); + AssertEx.SetEqual(expectedFields, fields); + }; + } + + private static Action VerifyNoCacheContainersIn(string containingTypeName) + { + return module => + { + var containingType = module.GlobalNamespace.GetMember(containingTypeName); + AssertEx.NotNull(containingType); + + var nestedTypes = containingType.GetTypeMembers(); + Assert.DoesNotContain(nestedTypes, t => t.Name.StartsWith("<") && t.Name.Contains(">O")); + }; + } + +} diff --git a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenNullCheckedParameterTests.cs b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenNullCheckedParameterTests.cs index 647511c5f8785..1a2d9ed14b9e1 100644 --- a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenNullCheckedParameterTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenNullCheckedParameterTests.cs @@ -1308,11 +1308,11 @@ public static void Main() { // Code size 26 (0x1a) .maxstack 3 - IL_0000: ldc.i4.s -2 - IL_0002: newobj ""C.d__0..ctor(int)"" - IL_0007: ldarg.1 - IL_0008: ldstr ""s"" - IL_000d: call ""ThrowIfNull"" + IL_0000: ldarg.1 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldc.i4.s -2 + IL_000d: newobj ""C.d__0..ctor(int)"" IL_0012: dup IL_0013: ldarg.1 IL_0014: stfld ""string C.d__0.<>3__s"" @@ -1343,11 +1343,11 @@ async IAsyncEnumerable GetChars(string s!!, Task t) { // Code size 33 (0x21) .maxstack 3 - IL_0000: ldc.i4.s -2 - IL_0002: newobj ""C.d__0..ctor(int)"" - IL_0007: ldarg.1 - IL_0008: ldstr ""s"" - IL_000d: call ""ThrowIfNull"" + IL_0000: ldarg.1 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldc.i4.s -2 + IL_000d: newobj ""C.d__0..ctor(int)"" IL_0012: dup IL_0013: ldarg.1 IL_0014: stfld ""string C.d__0.<>3__s"" @@ -1376,18 +1376,17 @@ IEnumerable GetChars(string s!!) } } } - }"; var compilation = CompileAndVerify(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyIL("Iterators.g__GetChars|0_0(string)", @" { // Code size 26 (0x1a) .maxstack 3 - IL_0000: ldc.i4.s -2 - IL_0002: newobj ""Iterators.<g__GetChars|0_0>d..ctor(int)"" - IL_0007: ldarg.0 - IL_0008: ldstr ""s"" - IL_000d: call ""ThrowIfNull"" + IL_0000: ldarg.0 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldc.i4.s -2 + IL_000d: newobj ""Iterators.<g__GetChars|0_0>d..ctor(int)"" IL_0012: dup IL_0013: ldarg.0 IL_0014: stfld ""string Iterators.<g__GetChars|0_0>d.<>3__s"" @@ -1399,12 +1398,26 @@ .maxstack 3 public void TestNullCheckedEnumeratorInLocalFunction() { var source = @" +using System; using System.Collections.Generic; + +Iterators.Use(); + class Iterators { - void Use() + public static void Use() { IEnumerator e = GetChars(""hello""); + Console.Write(1); + + try + { + GetChars(null!); + } + catch (ArgumentNullException) + { + Console.Write(2); + } IEnumerator GetChars(string s!!) { foreach (var c in s) @@ -1415,16 +1428,16 @@ IEnumerator GetChars(string s!!) } }"; - var compilation = CompileAndVerify(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyIL("Iterators.g__GetChars|0_0(string)", @" + var verifier = CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "12"); + verifier.VerifyIL("Iterators.g__GetChars|0_0(string)", @" { // Code size 25 (0x19) .maxstack 3 - IL_0000: ldc.i4.0 - IL_0001: newobj ""Iterators.<g__GetChars|0_0>d..ctor(int)"" - IL_0006: ldarg.0 - IL_0007: ldstr ""s"" - IL_000c: call ""ThrowIfNull"" + IL_0000: ldarg.0 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldc.i4.0 + IL_000c: newobj ""Iterators.<g__GetChars|0_0>d..ctor(int)"" IL_0011: dup IL_0012: ldarg.0 IL_0013: stfld ""string Iterators.<g__GetChars|0_0>d.s"" @@ -1537,12 +1550,12 @@ static IEnumerable GetChars(string s!!) CompileAndVerify(source, parseOptions: TestOptions.RegularPreview).VerifyIL("C.GetChars(string)", @" { // Code size 19 (0x13) - .maxstack 3 - IL_0000: ldc.i4.s -2 - IL_0002: newobj ""C.d__1..ctor(int)"" - IL_0007: ldarg.0 - IL_0008: ldstr ""s"" - IL_000d: call ""ThrowIfNull"" + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldc.i4.s -2 + IL_000d: newobj ""C.d__1..ctor(int)"" IL_0012: ret }"); } @@ -1563,12 +1576,12 @@ static IEnumerator GetChars(string s!!) CompileAndVerify(source, parseOptions: TestOptions.RegularPreview).VerifyIL("C.GetChars(string)", @" { // Code size 18 (0x12) - .maxstack 3 - IL_0000: ldc.i4.0 - IL_0001: newobj ""C.d__1..ctor(int)"" - IL_0006: ldarg.0 - IL_0007: ldstr ""s"" - IL_000c: call ""ThrowIfNull"" + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldc.i4.0 + IL_000c: newobj ""C.d__1..ctor(int)"" IL_0011: ret }"); } @@ -2027,6 +2040,409 @@ .maxstack 2 IL_001e: ldarg.2 IL_001f: stfld ""string RecordStruct.k__BackingField"" IL_0024: ret +}"); + } + + [Fact, WorkItem(58824, "https://github.com/dotnet/roslyn/issues/58824")] + public void TestWithEmbeddedReference() + { + var source = @" +using System; + +C.M(""a""); +Console.Write(1); +try +{ + C.M(null); + Console.Write(0); +} +catch +{ + Console.Write(2); +} + +class C +{ + public static void M(string s!!) + { + } +} +"; + var verifier = CompileAndVerify(source, references: new[] { TestReferences.SymbolsTests.NoPia.GeneralPia.WithEmbedInteropTypes(true) }, expectedOutput: "12"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.M", @" +{ + // Code size 12 (0xc) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ret +} +"); + } + + [Fact] + public void AsyncMethod_1() + { + var source = @" +using System; +using System.Threading.Tasks; + +var c = new C(); +try +{ + await c.M(""a""); + Console.Write(1); +} +catch (ArgumentNullException) +{ + Console.Write(0); +} + +try +{ + _ = c.M(null!); + Console.Write(0); +} +catch (ArgumentNullException) +{ + Console.Write(2); +} + +class C +{ + public async Task M(string s!!) + { + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: "12"); + verifier.VerifyDiagnostics( + // (28,23): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. + // public async Task M(string s!!) + Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(28, 23)); + verifier.VerifyIL("C.M", @" +{ + // Code size 58 (0x3a) + .maxstack 2 + .locals init (C.d__0 V_0) + IL_0000: ldarg.1 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldloca.s V_0 + IL_000d: call ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Create()"" + IL_0012: stfld ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_0017: ldloca.s V_0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.d__0.<>1__state"" + IL_001f: ldloca.s V_0 + IL_0021: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_0026: ldloca.s V_0 + IL_0028: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Startd__0>(ref C.d__0)"" + IL_002d: ldloca.s V_0 + IL_002f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_0034: call ""System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Task.get"" + IL_0039: ret +} +"); + } + + [Fact] + public void AsyncLocalFunction() + { + var source = @" +using System; +using System.Threading.Tasks; + +await C.M(); + +class C +{ + public static async Task M() + { + try + { + await local(""a""); + Console.Write(1); + } + catch (ArgumentNullException) + { + Console.Write(0); + } + + try + { + _ = local(null!); + Console.Write(0); + } + catch (ArgumentNullException) + { + Console.Write(2); + } + + async Task local(string s!!) { } + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: "12"); + verifier.VerifyDiagnostics( + // (31,20): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. + // async Task local(string s!!) { } + Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "local").WithLocation(31, 20)); + verifier.VerifyIL("C.g__local|0_0", @" +{ + // Code size 58 (0x3a) + .maxstack 2 + .locals init (C.<g__local|0_0>d V_0) + IL_0000: ldarg.0 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldloca.s V_0 + IL_000d: call ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Create()"" + IL_0012: stfld ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<g__local|0_0>d.<>t__builder"" + IL_0017: ldloca.s V_0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.<g__local|0_0>d.<>1__state"" + IL_001f: ldloca.s V_0 + IL_0021: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<g__local|0_0>d.<>t__builder"" + IL_0026: ldloca.s V_0 + IL_0028: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Startg__local|0_0>d>(ref C.<g__local|0_0>d)"" + IL_002d: ldloca.s V_0 + IL_002f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<g__local|0_0>d.<>t__builder"" + IL_0034: call ""System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Task.get"" + IL_0039: ret +} +"); + } + + [Fact] + public void AsyncLambda() + { + var source = @" +using System; +using System.Threading.Tasks; + +await C.M(); + +class C +{ + public static async Task M() + { + var lambda = async Task (string s!!) => { }; + try + { + await lambda(""a""); + Console.Write(1); + } + catch (ArgumentNullException) + { + Console.Write(0); + } + + try + { + _ = lambda(null!); + Console.Write(0); + } + catch (ArgumentNullException) + { + Console.Write(2); + } + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: "12"); + verifier.VerifyDiagnostics( + // (11,46): 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. + // var lambda = async Task (string s!!) => { }; + Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "=>").WithLocation(11, 46)); + verifier.VerifyIL("C.<>c.b__0_0", @" +{ + // Code size 58 (0x3a) + .maxstack 2 + .locals init (C.<>c.<b__0_0>d V_0) + IL_0000: ldarg.1 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldloca.s V_0 + IL_000d: call ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Create()"" + IL_0012: stfld ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<>c.<b__0_0>d.<>t__builder"" + IL_0017: ldloca.s V_0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.<>c.<b__0_0>d.<>1__state"" + IL_001f: ldloca.s V_0 + IL_0021: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<>c.<b__0_0>d.<>t__builder"" + IL_0026: ldloca.s V_0 + IL_0028: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Startc.<b__0_0>d>(ref C.<>c.<b__0_0>d)"" + IL_002d: ldloca.s V_0 + IL_002f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<>c.<b__0_0>d.<>t__builder"" + IL_0034: call ""System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Task.get"" + IL_0039: ret +} +"); + } + + [Fact] + public void AsyncMethod_2() + { + var source = @" +using System; +using System.Threading.Tasks; + +var c = new C(); +try +{ + await c.M(""a""); + Console.Write(1); +} +catch (ArgumentNullException) +{ + Console.Write(0); +} + +try +{ + _ = c.M(null!); + Console.Write(0); +} +catch (ArgumentNullException) +{ + Console.Write(2); +} + +class C +{ + public async Task M(string s!!) + { + if (s == """") + return; + await Task.CompletedTask; + return; + } +} +"; + var verifier = CompileAndVerify(source, expectedOutput: "12"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.M", @" +{ + // Code size 66 (0x42) + .maxstack 2 + .locals init (C.d__0 V_0) + IL_0000: ldarg.1 + IL_0001: ldstr ""s"" + IL_0006: call ""ThrowIfNull"" + IL_000b: ldloca.s V_0 + IL_000d: call ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Create()"" + IL_0012: stfld ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_0017: ldloca.s V_0 + IL_0019: ldarg.1 + IL_001a: stfld ""string C.d__0.s"" + IL_001f: ldloca.s V_0 + IL_0021: ldc.i4.m1 + IL_0022: stfld ""int C.d__0.<>1__state"" + IL_0027: ldloca.s V_0 + IL_0029: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_002e: ldloca.s V_0 + IL_0030: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Startd__0>(ref C.d__0)"" + IL_0035: ldloca.s V_0 + IL_0037: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_003c: call ""System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Task.get"" + IL_0041: ret +} +"); + } + + [Fact] + public void TestNullCheckedRefString() + { + var source = @" +using System; + +class C +{ + public static void Main() + { + var s = ""1""; + Console.Write(s); + M(ref s); + Console.Write(s); + s = null; + try + { + M(ref s!); + Console.Write(0); + } + catch (ArgumentNullException) + { + Console.Write(3); + } + } + + public static void M(ref string x!!) + { + x = ""2""; + } +}"; + var verifier = CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "123"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", @" +{ + // Code size 20 (0x14) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldind.ref + IL_0002: ldstr ""x"" + IL_0007: call ""ThrowIfNull"" + IL_000c: ldarg.0 + IL_000d: ldstr ""2"" + IL_0012: stind.ref + IL_0013: ret +}"); + } + + [Fact] + public void TestNullCheckedInString() + { + var source = @" +using System; + +class C +{ + public static void Main() + { + var s = ""1""; + Console.Write(s); + M(in s); + s = null; + try + { + M(in s!); + Console.Write(0); + } + catch (ArgumentNullException) + { + Console.Write(2); + } + } + + public static void M(in string x!!) + { + } +}"; + var verifier = CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "12"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", @" +{ + // Code size 13 (0xd) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldind.ref + IL_0002: ldstr ""x"" + IL_0007: call ""ThrowIfNull"" + IL_000c: ret }"); } } diff --git a/src/Compilers/CSharp/Test/Emit/Emit/UnmanagedTypeModifierTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/UnmanagedTypeModifierTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit/Emit/UnmanagedTypeModifierTests.cs rename to src/Compilers/CSharp/Test/Emit2/Emit/UnmanagedTypeModifierTests.cs diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IVariableDeclaration.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IVariableDeclaration.cs index 06d72bea0319d..72c52bd669f32 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IVariableDeclaration.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IVariableDeclaration.cs @@ -610,9 +610,9 @@ void M1() var compilation = CreateEmptyCompilation(source); (var operation, _) = GetOperationAndSyntaxForTest(compilation); var declarator = (IVariableDeclaratorOperation)operation; - Assert.Equal(2, declarator.Children.Count()); - Assert.Equal(OperationKind.Literal, declarator.Children.First().Kind); - Assert.Equal(OperationKind.VariableInitializer, declarator.Children.ElementAt(1).Kind); + Assert.Equal(2, declarator.ChildOperations.Count()); + Assert.Equal(OperationKind.Literal, declarator.ChildOperations.First().Kind); + Assert.Equal(OperationKind.VariableInitializer, declarator.ChildOperations.ElementAt(1).Kind); } [CompilerTrait(CompilerFeature.IOperation)] @@ -632,8 +632,8 @@ void M1() var compilation = CreateEmptyCompilation(source); (var operation, _) = GetOperationAndSyntaxForTest(compilation); var declarator = (IVariableDeclaratorOperation)operation; - Assert.Equal(1, declarator.Children.Count()); - Assert.Equal(OperationKind.Literal, declarator.Children.First().Kind); + Assert.Equal(1, declarator.ChildOperations.Count()); + Assert.Equal(OperationKind.Literal, declarator.ChildOperations.First().Kind); } [CompilerTrait(CompilerFeature.IOperation)] @@ -653,8 +653,8 @@ void M1() var compilation = CreateEmptyCompilation(source); (var operation, _) = GetOperationAndSyntaxForTest(compilation); var declarator = (IVariableDeclaratorOperation)operation; - Assert.Equal(1, declarator.Children.Count()); - Assert.Equal(OperationKind.VariableInitializer, declarator.Children.ElementAt(0).Kind); + Assert.Equal(1, declarator.ChildOperations.Count()); + Assert.Equal(OperationKind.VariableInitializer, declarator.ChildOperations.ElementAt(0).Kind); } [CompilerTrait(CompilerFeature.IOperation)] @@ -673,7 +673,7 @@ void M1() var compilation = CreateEmptyCompilation(source); (var operation, _) = GetOperationAndSyntaxForTest(compilation); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } [CompilerTrait(CompilerFeature.IOperation)] @@ -848,9 +848,9 @@ void M1() var compilation = CreateEmptyCompilation(source); (var operation, _) = GetOperationAndSyntaxForTest(compilation); var declaration = (IVariableDeclarationOperation)operation; - Assert.Equal(2, declaration.Children.Count()); - Assert.Equal(OperationKind.Literal, declaration.Children.First().Kind); - Assert.Equal(OperationKind.VariableDeclarator, declaration.Children.ElementAt(1).Kind); + Assert.Equal(2, declaration.ChildOperations.Count()); + Assert.Equal(OperationKind.Literal, declaration.ChildOperations.First().Kind); + Assert.Equal(OperationKind.VariableDeclarator, declaration.ChildOperations.ElementAt(1).Kind); } [CompilerTrait(CompilerFeature.IOperation)] @@ -870,9 +870,9 @@ void M1() var compilation = CreateEmptyCompilation(source); (var operation, _) = GetOperationAndSyntaxForTest(compilation); var declaration = (IVariableDeclarationOperation)operation; - Assert.Equal(2, declaration.Children.Count()); - Assert.Equal(OperationKind.Literal, declaration.Children.First().Kind); - Assert.Equal(OperationKind.VariableDeclarator, declaration.Children.ElementAt(1).Kind); + Assert.Equal(2, declaration.ChildOperations.Count()); + Assert.Equal(OperationKind.Literal, declaration.ChildOperations.First().Kind); + Assert.Equal(OperationKind.VariableDeclarator, declaration.ChildOperations.ElementAt(1).Kind); } [CompilerTrait(CompilerFeature.IOperation)] diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_NullCheckedParameters.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_NullCheckedParameters.cs index 297a80c6d18f6..491e2fc426039 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_NullCheckedParameters.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_NullCheckedParameters.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -41,2606 +41,8 @@ public void M(string input!!) { } Block[B0] - Entry Statements (0) Next (Regular) Block[B1] -Block[B1] - Block +Block[B1] - Exit Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public void ... nput!!) { }') - Left: - IParameterReferenceOperation: input (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public void ... nput!!) { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public void ... nput!!) { }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public void ... nput!!) { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public void ... nput!!) { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""input"", IsImplicit) (Syntax: 'public void ... nput!!) { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_OneNullCheckedManyParams() - { - var source = @" -public class C -{ - public void M(string x, string y!!) { } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'public void ... ng y!!) { }') - BlockBody: - IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public void ... ng y!!) { }') - Left: - IParameterReferenceOperation: y (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public void ... ng y!!) { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public void ... ng y!!) { }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public void ... ng y!!) { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public void ... ng y!!) { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""y"", IsImplicit) (Syntax: 'public void ... ng y!!) { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_OneNullCheckedParamWithStringOpt() - { - var source = @" -public class C -{ - public void M(string name!! = ""rose"") { } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'public void ... ""rose"") { }') - BlockBody: - IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public void ... ""rose"") { }') - Left: - IParameterReferenceOperation: name (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public void ... ""rose"") { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public void ... ""rose"") { }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public void ... ""rose"") { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public void ... ""rose"") { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""name"", IsImplicit) (Syntax: 'public void ... ""rose"") { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedOperator() - { - var source = @" -public class Box -{ - public static int operator+ (Box b!!, Box c) - { - return 2; - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'public stat ... }') - BlockBody: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return 2;') - ReturnedValue: - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public stat ... }') - Left: - IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: Box, IsImplicit) (Syntax: 'public stat ... }') - Right: - ILiteralOperation (OperationKind.Literal, Type: Box, Constant: null, IsImplicit) (Syntax: 'public stat ... }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public stat ... }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public stat ... }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""b"", IsImplicit) (Syntax: 'public stat ... }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Block - Predecessors: [B1] - Statements (0) - Next (Return) Block[B4] - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') -Block[B4] - Exit - Predecessors: [B3] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedIndexedProperty() - { - // https://github.com/dotnet/roslyn/issues/58320 - var source = @" -public class C -{ - public string this[string index!!] => null; -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '=> null') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'null') - ReturnedValue: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, Constant: null, IsImplicit) (Syntax: 'null') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) - Operand: - ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Next (Return) Block[B2] - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, Constant: null, IsImplicit) (Syntax: 'null') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) - (ImplicitReference) - Operand: - ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null') -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedIndexedGetterSetter() - { - var source = @" -public class C -{ - private object[] items = {'h', ""hello""}; - public string this[object item!!] - { - /**/get - { - return items[0].ToString(); - }/**/ - set - { - items[0] = value; - } - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'set ... }') - BlockBody: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'items[0] = value;') - Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Object) (Syntax: 'items[0] = value') - Left: - IArrayElementReferenceOperation (OperationKind.ArrayElementReference, Type: System.Object) (Syntax: 'items[0]') - Array reference: - IFieldReferenceOperation: System.Object[] C.items (OperationKind.FieldReference, Type: System.Object[]) (Syntax: 'items') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'items') - Indices(1): - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') - Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'value') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) - Operand: - IParameterReferenceOperation: value (OperationKind.ParameterReference, Type: System.String) (Syntax: 'value') - ExpressionBody: - null"); - var expected = @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'get ... }') - Left: - IParameterReferenceOperation: item (OperationKind.ParameterReference, Type: System.Object, IsImplicit) (Syntax: 'get ... }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'get ... }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'get ... }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'get ... }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""item"", IsImplicit) (Syntax: 'get ... }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Block - Predecessors: [B1] - Statements (0) - Next (Return) Block[B4] - IInvocationOperation (virtual System.String System.Object.ToString()) (OperationKind.Invocation, Type: System.String) (Syntax: 'items[0].ToString()') - Instance Receiver: - IArrayElementReferenceOperation (OperationKind.ArrayElementReference, Type: System.Object) (Syntax: 'items[0]') - Array reference: - IFieldReferenceOperation: System.Object[] C.items (OperationKind.FieldReference, Type: System.Object[]) (Syntax: 'items') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'items') - Indices(1): - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') - Arguments(0) -Block[B4] - Exit - Predecessors: [B3] - Statements (0)"; - VerifyFlowGraphAndDiagnosticsForTest(source, expected, DiagnosticDescription.None, parseOptions: TestOptions.RegularPreview); - } - - [Fact] - public void TestIOp_NullCheckedIndexedGetterExpression() - { - var source = @" -public class C -{ - private object[] items = {'h', ""hello""}; - public string this[object item!!] - { - /**/get => items[0].ToString();/**/ - set - { - items[0] = value; - } - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'set ... }') - BlockBody: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'items[0] = value;') - Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Object) (Syntax: 'items[0] = value') - Left: - IArrayElementReferenceOperation (OperationKind.ArrayElementReference, Type: System.Object) (Syntax: 'items[0]') - Array reference: - IFieldReferenceOperation: System.Object[] C.items (OperationKind.FieldReference, Type: System.Object[]) (Syntax: 'items') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'items') - Indices(1): - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') - Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'value') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) - Operand: - IParameterReferenceOperation: value (OperationKind.ParameterReference, Type: System.String) (Syntax: 'value') - ExpressionBody: - null"); - var expected = @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'get => item ... ToString();') - Left: - IParameterReferenceOperation: item (OperationKind.ParameterReference, Type: System.Object, IsImplicit) (Syntax: 'get => item ... ToString();') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'get => item ... ToString();') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'get => item ... ToString();') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'get => item ... ToString();') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""item"", IsImplicit) (Syntax: 'get => item ... ToString();') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Block - Predecessors: [B1] - Statements (0) - Next (Return) Block[B4] - IInvocationOperation (virtual System.String System.Object.ToString()) (OperationKind.Invocation, Type: System.String) (Syntax: 'items[0].ToString()') - Instance Receiver: - IArrayElementReferenceOperation (OperationKind.ArrayElementReference, Type: System.Object) (Syntax: 'items[0]') - Array reference: - IFieldReferenceOperation: System.Object[] C.items (OperationKind.FieldReference, Type: System.Object[]) (Syntax: 'items') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'items') - Indices(1): - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') - Arguments(0) -Block[B4] - Exit - Predecessors: [B3] - Statements (0)"; - - VerifyFlowGraphAndDiagnosticsForTest(source, expected, DiagnosticDescription.None, parseOptions: TestOptions.RegularPreview); - } - - [Fact] - public void TestIOp_NullCheckedIndexedSetter() - { - var source = @" -public class C -{ - public string this[object item!!] { /**/set { }/**/ } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'set { }') - BlockBody: - IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - ExpressionBody: - null"); - var expected = @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'set { }') - Left: - IParameterReferenceOperation: item (OperationKind.ParameterReference, Type: System.Object, IsImplicit) (Syntax: 'set { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'set { }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'set { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'set { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""item"", IsImplicit) (Syntax: 'set { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Exit - Predecessors: [B1] - Statements (0)"; - VerifyFlowGraphAndDiagnosticsForTest(source, expected, DiagnosticDescription.None, parseOptions: TestOptions.RegularPreview); - } - - [Fact] - public void TestIOp_NullCheckedLambda() - { - var source = @" -using System; -class C -{ - public void M() - { - Func func1 = x!! => x; - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" -IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'public void ... }') - BlockBody: - IBlockOperation (1 statements, 1 locals) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - Locals: Local_1: System.Func func1 - IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'Func x;') - IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'Func x') - Declarators: - IVariableDeclaratorOperation (Symbol: System.Func func1) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'func1 = x!! => x') - Initializer: - IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= x!! => x') - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: 'x!! => x') - Target: - IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null) (Syntax: 'x!! => x') - IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'x') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x') - ReturnedValue: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x') - Initializer: - null - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} -{ - Locals: [System.Func func1] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Func, IsImplicit) (Syntax: 'func1 = x!! => x') - Left: - ILocalReferenceOperation: func1 (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Func, IsImplicit) (Syntax: 'func1 = x!! => x') - Right: - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: 'x!! => x') - Target: - IFlowAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.FlowAnonymousFunction, Type: null) (Syntax: 'x!! => x') - { - Block[B0#A0] - Entry - Statements (0) - Next (Regular) Block[B1#A0] - Block[B1#A0] - Block - Predecessors: [B0#A0] - Statements (0) - Jump if False (Regular) to Block[B3#A0] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'x!! => x') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'x!! => x') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'x!! => x') - Next (Regular) Block[B2#A0] - Block[B2#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'x!! => x') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'x!! => x') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'x!! => x') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B3#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Return) Block[B4#A0] - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x') - Block[B4#A0] - Exit - Predecessors: [B3#A0] - Statements (0) - } - Next (Regular) Block[B2] - Leaving: {R1} -} -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedInLambdaWithManyParameters() - { - var source = @" -using System; -class C -{ - public void M() - { - Func func1 = (x!!, y) => x; - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'public void ... }') - BlockBody: - IBlockOperation (1 statements, 1 locals) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - Locals: Local_1: System.Func func1 - IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'Func x;') - IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'Func x') - Declarators: - IVariableDeclaratorOperation (Symbol: System.Func func1) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'func1 = (x!!, y) => x') - Initializer: - IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= (x!!, y) => x') - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: '(x!!, y) => x') - Target: - IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null) (Syntax: '(x!!, y) => x') - IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'x') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x') - ReturnedValue: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x') - Initializer: - null - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} -{ - Locals: [System.Func func1] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Func, IsImplicit) (Syntax: 'func1 = (x!!, y) => x') - Left: - ILocalReferenceOperation: func1 (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Func, IsImplicit) (Syntax: 'func1 = (x!!, y) => x') - Right: - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: '(x!!, y) => x') - Target: - IFlowAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.FlowAnonymousFunction, Type: null) (Syntax: '(x!!, y) => x') - { - Block[B0#A0] - Entry - Statements (0) - Next (Regular) Block[B1#A0] - Block[B1#A0] - Block - Predecessors: [B0#A0] - Statements (0) - Jump if False (Regular) to Block[B3#A0] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: '(x!!, y) => x') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: '(x!!, y) => x') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: '(x!!, y) => x') - Next (Regular) Block[B2#A0] - Block[B2#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: '(x!!, y) => x') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '(x!!, y) => x') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: '(x!!, y) => x') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B3#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Return) Block[B4#A0] - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x') - Block[B4#A0] - Exit - Predecessors: [B3#A0] - Statements (0) - } - Next (Regular) Block[B2] - Leaving: {R1} -} -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedUnnamedVariableInLambda() - { - var source = @" -using System; -class C -{ - public void M() - { - Func func1 = _!! => null; - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'public void ... }') - BlockBody: - IBlockOperation (1 statements, 1 locals) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - Locals: Local_1: System.Func func1 - IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'Func null;') - IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'Func null') - Declarators: - IVariableDeclaratorOperation (Symbol: System.Func func1) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'func1 = _!! => null') - Initializer: - IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= _!! => null') - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: '_!! => null') - Target: - IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null) (Syntax: '_!! => null') - IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'null') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'null') - ReturnedValue: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, Constant: null, IsImplicit) (Syntax: 'null') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) - Operand: - ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null') - Initializer: - null - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} -{ - Locals: [System.Func func1] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Func, IsImplicit) (Syntax: 'func1 = _!! => null') - Left: - ILocalReferenceOperation: func1 (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Func, IsImplicit) (Syntax: 'func1 = _!! => null') - Right: - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: '_!! => null') - Target: - IFlowAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.FlowAnonymousFunction, Type: null) (Syntax: '_!! => null') - { - Block[B0#A0] - Entry - Statements (0) - Next (Regular) Block[B1#A0] - Block[B1#A0] - Block - Predecessors: [B0#A0] - Statements (0) - Jump if False (Regular) to Block[B3#A0] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: '_!! => null') - Left: - IParameterReferenceOperation: _ (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: '_!! => null') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: '_!! => null') - Next (Regular) Block[B2#A0] - Block[B2#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: '_!! => null') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '_!! => null') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""_"", IsImplicit) (Syntax: '_!! => null') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B3#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Return) Block[B4#A0] - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, Constant: null, IsImplicit) (Syntax: 'null') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) - (ImplicitReference) - Operand: - ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null') - Block[B4#A0] - Exit - Predecessors: [B3#A0] - Statements (0) - } - Next (Regular) Block[B2] - Leaving: {R1} -} -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedTwoExpressionBodyLambdas() - { - var source = @" -using System; -class C -{ - public Func M(string s1!!) => s2!! => s2 + s1; -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'public Func ... => s2 + s1;') - BlockBody: - null - ExpressionBody: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '=> s2!! => s2 + s1') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 's2!! => s2 + s1') - ReturnedValue: - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: 's2!! => s2 + s1') - Target: - IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null) (Syntax: 's2!! => s2 + s1') - IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 's2 + s1') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 's2 + s1') - ReturnedValue: - IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: 's2 + s1') - Left: - IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: System.String) (Syntax: 's2') - Right: - IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: System.String) (Syntax: 's1')"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public Func ... => s2 + s1;') - Left: - IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public Func ... => s2 + s1;') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public Func ... => s2 + s1;') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public Func ... => s2 + s1;') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public Func ... => s2 + s1;') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""s1"", IsImplicit) (Syntax: 'public Func ... => s2 + s1;') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Block - Predecessors: [B1] - Statements (0) - Next (Return) Block[B4] - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: 's2!! => s2 + s1') - Target: - IFlowAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.FlowAnonymousFunction, Type: null) (Syntax: 's2!! => s2 + s1') - { - Block[B0#A0] - Entry - Statements (0) - Next (Regular) Block[B1#A0] - Block[B1#A0] - Block - Predecessors: [B0#A0] - Statements (0) - Jump if False (Regular) to Block[B3#A0] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 's2!! => s2 + s1') - Left: - IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 's2!! => s2 + s1') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 's2!! => s2 + s1') - Next (Regular) Block[B2#A0] - Block[B2#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 's2!! => s2 + s1') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 's2!! => s2 + s1') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""s2"", IsImplicit) (Syntax: 's2!! => s2 + s1') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B3#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Return) Block[B4#A0] - IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: 's2 + s1') - Left: - IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: System.String) (Syntax: 's2') - Right: - IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: System.String) (Syntax: 's1') - Block[B4#A0] - Exit - Predecessors: [B3#A0] - Statements (0) - } -Block[B4] - Exit - Predecessors: [B3] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedLambdaInField() - { - var source = @" -using System; -class C -{ - Func func1 = x!! => x; - public C() - { - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - var node2 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null) (Syntax: 'x!! => x') - IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'x') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x') - ReturnedValue: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x')"); - - VerifyFlowGraph(compilation, node2, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (1) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Func, IsImplicit) (Syntax: '= x!! => x') - Left: - IFieldReferenceOperation: System.Func C.func1 (OperationKind.FieldReference, Type: System.Func, IsImplicit) (Syntax: '= x!! => x') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: '= x!! => x') - Right: - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: 'x!! => x') - Target: - IFlowAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.FlowAnonymousFunction, Type: null) (Syntax: 'x!! => x') - { - Block[B0#A0] - Entry - Statements (0) - Next (Regular) Block[B1#A0] - Block[B1#A0] - Block - Predecessors: [B0#A0] - Statements (0) - Jump if False (Regular) to Block[B3#A0] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'x!! => x') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'x!! => x') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'x!! => x') - Next (Regular) Block[B2#A0] - Block[B2#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'x!! => x') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'x!! => x') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'x!! => x') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B3#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Return) Block[B4#A0] - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x') - Block[B4#A0] - Exit - Predecessors: [B3#A0] - Statements (0) - } - Next (Regular) Block[B2] -Block[B2] - Exit - Predecessors: [B1] - Statements (0) -"); - } - - [Fact] - public void TestIOp_NullCheckedLocalFunction() - { - var source = @" -class C -{ - public void M() - { - InnerM(""hello world""); - void InnerM(string x!!) { } - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - var node2 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - ILocalFunctionOperation (Symbol: void InnerM(System.String x)) (OperationKind.LocalFunction, Type: null) (Syntax: 'void InnerM ... ng x!!) { }') - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: '{ }') - ReturnedValue: - null"); - VerifyFlowGraph(compilation, node2, @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} -{ - Methods: [void InnerM(System.String x)] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'InnerM(""hello world"");') - Expression: - IInvocationOperation (void InnerM(System.String x)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'InnerM(""hello world"")') - Instance Receiver: - null - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: '""hello world""') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""hello world"") (Syntax: '""hello world""') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Next (Regular) Block[B2] - Leaving: {R1} - - { void InnerM(System.String x) - - Block[B0#0R1] - Entry - Statements (0) - Next (Regular) Block[B1#0R1] - Block[B1#0R1] - Block - Predecessors: [B0#0R1] - Statements (0) - Jump if False (Regular) to Block[B3#0R1] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - Next (Regular) Block[B2#0R1] - Block[B2#0R1] - Block - Predecessors: [B1#0R1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B3#0R1] - Exit - Predecessors: [B1#0R1] - Statements (0) - } -} -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedManyParamsInLocalFunction() - { - var source = @" -class C -{ - public void M() - { - InnerM(""hello"", ""world""); - void InnerM(string x!!, string y!!) { } - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - var node2 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - ILocalFunctionOperation (Symbol: void InnerM(System.String x, System.String y)) (OperationKind.LocalFunction, Type: null) (Syntax: 'void InnerM ... ng y!!) { }') - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: '{ }') - ReturnedValue: - null"); - - VerifyFlowGraph(compilation, node2, @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} -{ - Methods: [void InnerM(System.String x, System.String y)] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'InnerM(""hel ... ""world"");') - Expression: - IInvocationOperation (void InnerM(System.String x, System.String y)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'InnerM(""hel ... , ""world"")') - Instance Receiver: - null - Arguments(2): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: '""hello""') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""hello"") (Syntax: '""hello""') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: y) (OperationKind.Argument, Type: null) (Syntax: '""world""') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""world"") (Syntax: '""world""') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Next (Regular) Block[B2] - Leaving: {R1} - - { void InnerM(System.String x, System.String y) - - Block[B0#0R1] - Entry - Statements (0) - Next (Regular) Block[B1#0R1] - Block[B1#0R1] - Block - Predecessors: [B0#0R1] - Statements (0) - Jump if False (Regular) to Block[B3#0R1] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - Next (Regular) Block[B2#0R1] - Block[B2#0R1] - Block - Predecessors: [B1#0R1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B3#0R1] - Block - Predecessors: [B1#0R1] - Statements (0) - Jump if False (Regular) to Block[B5#0R1] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - Left: - IParameterReferenceOperation: y (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - Next (Regular) Block[B4#0R1] - Block[B4#0R1] - Block - Predecessors: [B3#0R1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""y"", IsImplicit) (Syntax: 'void InnerM ... ng y!!) { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B5#0R1] - Exit - Predecessors: [B3#0R1] - Statements (0) - } -} -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_OuterNullCheckedShadowedParameter() - { - var source = @" -class C -{ - public void M(string x!!) - { - InnerM(""hello""); - void InnerM(string x) { } - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'public void ... }') - BlockBody: - IBlockOperation (2 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'InnerM(""hello"");') - Expression: - IInvocationOperation (void InnerM(System.String x)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'InnerM(""hello"")') - Instance Receiver: - null - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: '""hello""') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""hello"") (Syntax: '""hello""') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - ILocalFunctionOperation (Symbol: void InnerM(System.String x)) (OperationKind.LocalFunction, Type: null) (Syntax: 'void InnerM ... ring x) { }') - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: '{ }') - ReturnedValue: - null - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public void ... }') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public void ... }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public void ... }') - Entering: {R1} - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public void ... }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public void ... }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'public void ... }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -.locals {R1} -{ - Methods: [void InnerM(System.String x)] - Block[B3] - Block - Predecessors: [B1] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'InnerM(""hello"");') - Expression: - IInvocationOperation (void InnerM(System.String x)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'InnerM(""hello"")') - Instance Receiver: - null - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: '""hello""') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""hello"") (Syntax: '""hello""') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Next (Regular) Block[B4] - Leaving: {R1} - - { void InnerM(System.String x) - - Block[B0#0R1] - Entry - Statements (0) - Next (Regular) Block[B1#0R1] - Block[B1#0R1] - Exit - Predecessors: [B0#0R1] - Statements (0) - } -} -Block[B4] - Exit - Predecessors: [B3] - Statements (0)"); - } - - [Fact] - public void TestIOp_InnerNullCheckedShadowedParameter() - { - var source = @" -class C -{ - public void M(string x) - { - InnerM(""hello""); - void InnerM(string x!!) { } - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - var node2 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - ILocalFunctionOperation (Symbol: void InnerM(System.String x)) (OperationKind.LocalFunction, Type: null) (Syntax: 'void InnerM ... ng x!!) { }') - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: '{ }') - ReturnedValue: - null"); - VerifyFlowGraph(compilation, node2, @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} -{ - Methods: [void InnerM(System.String x)] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'InnerM(""hello"");') - Expression: - IInvocationOperation (void InnerM(System.String x)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'InnerM(""hello"")') - Instance Receiver: - null - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: '""hello""') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""hello"") (Syntax: '""hello""') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Next (Regular) Block[B2] - Leaving: {R1} - - { void InnerM(System.String x) - - Block[B0#0R1] - Entry - Statements (0) - Next (Regular) Block[B1#0R1] - Block[B1#0R1] - Block - Predecessors: [B0#0R1] - Statements (0) - Jump if False (Regular) to Block[B3#0R1] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - Next (Regular) Block[B2#0R1] - Block[B2#0R1] - Block - Predecessors: [B1#0R1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'void InnerM ... ng x!!) { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B3#0R1] - Exit - Predecessors: [B1#0R1] - Statements (0) - } -} -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedConstructor() - { - var source = @" -class C -{ - public C(string x!!) { } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IConstructorBodyOperation (OperationKind.ConstructorBody, Type: null) (Syntax: 'public C(string x!!) { }') - Initializer: - null - BlockBody: - IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public C(string x!!) { }') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public C(string x!!) { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public C(string x!!) { }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public C(string x!!) { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public C(string x!!) { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'public C(string x!!) { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedConstructorWithThisChain() - { - var source = @" -class C -{ - public C() { } - public C(string x!!) : this() { } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IConstructorBodyOperation (OperationKind.ConstructorBody, Type: null) (Syntax: 'public C(st ... this() { }') - Initializer: - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: ': this()') - Expression: - IInvocationOperation ( C..ctor()) (OperationKind.Invocation, Type: System.Void) (Syntax: ': this()') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: ': this()') - Arguments(0) - BlockBody: - IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public C(st ... this() { }') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public C(st ... this() { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public C(st ... this() { }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public C(st ... this() { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public C(st ... this() { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'public C(st ... this() { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Block - Predecessors: [B1] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: ': this()') - Expression: - IInvocationOperation ( C..ctor()) (OperationKind.Invocation, Type: System.Void) (Syntax: ': this()') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: ': this()') - Arguments(0) - Next (Regular) Block[B4] -Block[B4] - Exit - Predecessors: [B3] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedConstructorWithBaseChain() - { - var source = @" -class B -{ - public B(string y) { } -} -class C : B -{ - public C(string x!!) : base(x) { } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IConstructorBodyOperation (OperationKind.ConstructorBody, Type: null) (Syntax: 'public C(st ... base(x) { }') - Initializer: - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: ': base(x)') - Expression: - IInvocationOperation ( B..ctor(System.String y)) (OperationKind.Invocation, Type: System.Void) (Syntax: ': base(x)') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: ': base(x)') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: y) (OperationKind.Argument, Type: null) (Syntax: 'x') - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - BlockBody: - IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public C(st ... base(x) { }') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public C(st ... base(x) { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public C(st ... base(x) { }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public C(st ... base(x) { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public C(st ... base(x) { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'public C(st ... base(x) { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Block - Predecessors: [B1] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: ': base(x)') - Expression: - IInvocationOperation ( B..ctor(System.String y)) (OperationKind.Invocation, Type: System.Void) (Syntax: ': base(x)') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: ': base(x)') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: y) (OperationKind.Argument, Type: null) (Syntax: 'x') - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Next (Regular) Block[B4] -Block[B4] - Exit - Predecessors: [B3] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedConstructorWithFieldInitializers() - { - var source = @" -class C -{ - int y = 5; - public C(string x!!) { y++; } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IConstructorBodyOperation (OperationKind.ConstructorBody, Type: null) (Syntax: 'public C(st ... !) { y++; }') - Initializer: - null - BlockBody: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ y++; }') - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'y++;') - Expression: - IIncrementOrDecrementOperation (Postfix) (OperationKind.Increment, Type: System.Int32) (Syntax: 'y++') - Target: - IFieldReferenceOperation: System.Int32 C.y (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'y') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'y') - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public C(st ... !) { y++; }') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public C(st ... !) { y++; }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public C(st ... !) { y++; }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public C(st ... !) { y++; }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public C(st ... !) { y++; }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'public C(st ... !) { y++; }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Block - Predecessors: [B1] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'y++;') - Expression: - IIncrementOrDecrementOperation (Postfix) (OperationKind.Increment, Type: System.Int32) (Syntax: 'y++') - Target: - IFieldReferenceOperation: System.Int32 C.y (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'y') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'y') - Next (Regular) Block[B4] -Block[B4] - Exit - Predecessors: [B3] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedExpressionBodyMethod() - { - var source = @" -class C -{ - object Local(object arg!!) => arg; -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'object Loca ... !!) => arg;') - BlockBody: - null - ExpressionBody: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '=> arg') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'arg') - ReturnedValue: - IParameterReferenceOperation: arg (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'arg')"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'object Loca ... !!) => arg;') - Left: - IParameterReferenceOperation: arg (OperationKind.ParameterReference, Type: System.Object, IsImplicit) (Syntax: 'object Loca ... !!) => arg;') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'object Loca ... !!) => arg;') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'object Loca ... !!) => arg;') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'object Loca ... !!) => arg;') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""arg"", IsImplicit) (Syntax: 'object Loca ... !!) => arg;') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Block - Predecessors: [B1] - Statements (0) - Next (Return) Block[B4] - IParameterReferenceOperation: arg (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'arg') -Block[B4] - Exit - Predecessors: [B3] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedIterator() - { - var source = @" -using System.Collections.Generic; -class C -{ - IEnumerable GetChars(string s!!) - { - foreach (var c in s) - { - yield return c; - } - } - public static void Main() - { - C c = new C(); - IEnumerable e = c.GetChars(""hello""); - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(0); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'IEnumerable ... }') - BlockBody: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IForEachLoopOperation (LoopKind.ForEach, Continue Label Id: 0, Exit Label Id: 1) (OperationKind.Loop, Type: null) (Syntax: 'foreach (va ... }') - Locals: Local_1: System.Char c - LoopControlVariable: - IVariableDeclaratorOperation (Symbol: System.Char c) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'var') - Initializer: - null - Collection: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 's') - Conversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - IParameterReferenceOperation: s (OperationKind.ParameterReference, Type: System.String) (Syntax: 's') - Body: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return c;') - ReturnedValue: - ILocalReferenceOperation: c (OperationKind.LocalReference, Type: System.Char) (Syntax: 'c') - NextVariables(0) - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'IEnumerable ... }') - Left: - IParameterReferenceOperation: s (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'IEnumerable ... }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'IEnumerable ... }') - Entering: {R1} - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'IEnumerable ... }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'IEnumerable ... }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""s"", IsImplicit) (Syntax: 'IEnumerable ... }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -.locals {R1} -{ - CaptureIds: [0] - Block[B3] - Block - Predecessors: [B1] - Statements (1) - IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 's') - Value: - IInvocationOperation ( System.CharEnumerator System.String.GetEnumerator()) (OperationKind.Invocation, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - Instance Receiver: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 's') - Conversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - (Identity) - Operand: - IParameterReferenceOperation: s (OperationKind.ParameterReference, Type: System.String) (Syntax: 's') - Arguments(0) - Next (Regular) Block[B4] - Entering: {R2} {R3} - .try {R2, R3} - { - Block[B4] - Block - Predecessors: [B3] [B5] - Statements (0) - Jump if False (Regular) to Block[B9] - IInvocationOperation ( System.Boolean System.CharEnumerator.MoveNext()) (OperationKind.Invocation, Type: System.Boolean, IsImplicit) (Syntax: 's') - Instance Receiver: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - Arguments(0) - Finalizing: {R5} - Leaving: {R3} {R2} {R1} - Next (Regular) Block[B5] - Entering: {R4} - .locals {R4} - { - Locals: [System.Char c] - Block[B5] - Block - Predecessors: [B4] - Statements (2) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: 'var') - Left: - ILocalReferenceOperation: c (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Char, IsImplicit) (Syntax: 'var') - Right: - IPropertyReferenceOperation: System.Char System.CharEnumerator.Current { get; } (OperationKind.PropertyReference, Type: System.Char, IsImplicit) (Syntax: 'var') - Instance Receiver: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return c;') - ReturnedValue: - ILocalReferenceOperation: c (OperationKind.LocalReference, Type: System.Char) (Syntax: 'c') - Next (Regular) Block[B4] - Leaving: {R4} - } - } - .finally {R5} - { - Block[B6] - Block - Predecessors (0) - Statements (0) - Jump if True (Regular) to Block[B8] - IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 's') - Operand: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - Next (Regular) Block[B7] - Block[B7] - Block - Predecessors: [B6] - Statements (1) - IInvocationOperation (virtual void System.IDisposable.Dispose()) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: 's') - Instance Receiver: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.IDisposable, IsImplicit) (Syntax: 's') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) - (ImplicitReference) - Operand: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - Arguments(0) - Next (Regular) Block[B8] - Block[B8] - Block - Predecessors: [B6] [B7] - Statements (0) - Next (StructuredExceptionHandling) Block[null] - } -} -Block[B9] - Exit - Predecessors: [B4] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedIteratorInLocalFunction() - { - var source = @" -using System.Collections.Generic; -class Iterators -{ - void Use() - { - IEnumerable e = GetChars(""hello""); - IEnumerable GetChars(string s!!) - { - foreach (var c in s) - { - yield return c; - } - } - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - var node2 = tree.GetRoot().DescendantNodes().OfType().Single(); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - ILocalFunctionOperation (Symbol: System.Collections.Generic.IEnumerable GetChars(System.String s)) (OperationKind.LocalFunction, Type: null) (Syntax: 'IEnumerable ... }') - IBlockOperation (2 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IForEachLoopOperation (LoopKind.ForEach, Continue Label Id: 0, Exit Label Id: 1) (OperationKind.Loop, Type: null) (Syntax: 'foreach (va ... }') - Locals: Local_1: System.Char c - LoopControlVariable: - IVariableDeclaratorOperation (Symbol: System.Char c) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'var') - Initializer: - null - Collection: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 's') - Conversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - IParameterReferenceOperation: s (OperationKind.ParameterReference, Type: System.String) (Syntax: 's') - Body: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return c;') - ReturnedValue: - ILocalReferenceOperation: c (OperationKind.LocalReference, Type: System.Char) (Syntax: 'c') - NextVariables(0) - IReturnOperation (OperationKind.YieldBreak, Type: null, IsImplicit) (Syntax: '{ ... }') - ReturnedValue: - null"); - - VerifyFlowGraph(compilation, node2, @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} -{ - Locals: [System.Collections.Generic.IEnumerable e] - Methods: [System.Collections.Generic.IEnumerable GetChars(System.String s)] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Collections.Generic.IEnumerable, IsImplicit) (Syntax: 'e = GetChars(""hello"")') - Left: - ILocalReferenceOperation: e (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Collections.Generic.IEnumerable, IsImplicit) (Syntax: 'e = GetChars(""hello"")') - Right: - IInvocationOperation (System.Collections.Generic.IEnumerable GetChars(System.String s)) (OperationKind.Invocation, Type: System.Collections.Generic.IEnumerable) (Syntax: 'GetChars(""hello"")') - Instance Receiver: - null - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: s) (OperationKind.Argument, Type: null) (Syntax: '""hello""') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""hello"") (Syntax: '""hello""') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Next (Regular) Block[B2] - Leaving: {R1} - - { System.Collections.Generic.IEnumerable GetChars(System.String s) - - Block[B0#0R1] - Entry - Statements (0) - Next (Regular) Block[B1#0R1] - Block[B1#0R1] - Block - Predecessors: [B0#0R1] - Statements (0) - Jump if False (Regular) to Block[B3#0R1] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'IEnumerable ... }') - Left: - IParameterReferenceOperation: s (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'IEnumerable ... }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'IEnumerable ... }') - Entering: {R1#0R1} - Next (Regular) Block[B2#0R1] - Block[B2#0R1] - Block - Predecessors: [B1#0R1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'IEnumerable ... }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'IEnumerable ... }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""s"", IsImplicit) (Syntax: 'IEnumerable ... }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - .locals {R1#0R1} - { - CaptureIds: [0] - Block[B3#0R1] - Block - Predecessors: [B1#0R1] - Statements (1) - IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 's') - Value: - IInvocationOperation ( System.CharEnumerator System.String.GetEnumerator()) (OperationKind.Invocation, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - Instance Receiver: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 's') - Conversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - (Identity) - Operand: - IParameterReferenceOperation: s (OperationKind.ParameterReference, Type: System.String) (Syntax: 's') - Arguments(0) - Next (Regular) Block[B4#0R1] - Entering: {R2#0R1} {R3#0R1} - .try {R2#0R1, R3#0R1} - { - Block[B4#0R1] - Block - Predecessors: [B3#0R1] [B5#0R1] - Statements (0) - Jump if False (Regular) to Block[B9#0R1] - IInvocationOperation ( System.Boolean System.CharEnumerator.MoveNext()) (OperationKind.Invocation, Type: System.Boolean, IsImplicit) (Syntax: 's') - Instance Receiver: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - Arguments(0) - Finalizing: {R5#0R1} - Leaving: {R3#0R1} {R2#0R1} {R1#0R1} - Next (Regular) Block[B5#0R1] - Entering: {R4#0R1} - .locals {R4#0R1} - { - Locals: [System.Char c] - Block[B5#0R1] - Block - Predecessors: [B4#0R1] - Statements (2) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: null, IsImplicit) (Syntax: 'var') - Left: - ILocalReferenceOperation: c (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Char, IsImplicit) (Syntax: 'var') - Right: - IPropertyReferenceOperation: System.Char System.CharEnumerator.Current { get; } (OperationKind.PropertyReference, Type: System.Char, IsImplicit) (Syntax: 'var') - Instance Receiver: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - IReturnOperation (OperationKind.YieldReturn, Type: null) (Syntax: 'yield return c;') - ReturnedValue: - ILocalReferenceOperation: c (OperationKind.LocalReference, Type: System.Char) (Syntax: 'c') - Next (Regular) Block[B4#0R1] - Leaving: {R4#0R1} - } - } - .finally {R5#0R1} - { - Block[B6#0R1] - Block - Predecessors (0) - Statements (0) - Jump if True (Regular) to Block[B8#0R1] - IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 's') - Operand: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - Next (Regular) Block[B7#0R1] - Block[B7#0R1] - Block - Predecessors: [B6#0R1] - Statements (1) - IInvocationOperation (virtual void System.IDisposable.Dispose()) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: 's') - Instance Receiver: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.IDisposable, IsImplicit) (Syntax: 's') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) - (ImplicitReference) - Operand: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.CharEnumerator, IsImplicit) (Syntax: 's') - Arguments(0) - Next (Regular) Block[B8#0R1] - Block[B8#0R1] - Block - Predecessors: [B6#0R1] [B7#0R1] - Statements (0) - Next (StructuredExceptionHandling) Block[null] - } - } - Block[B9#0R1] - Exit - Predecessors: [B4#0R1] - Statements (0) - } -} -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedEmptyIterator() - { - var source = @" -using System.Collections.Generic; -class C -{ - public static void Main() { } - static IEnumerable GetChars(string s!!) - { - yield break; - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'static IEnu ... }') - BlockBody: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IReturnOperation (OperationKind.YieldBreak, Type: null) (Syntax: 'yield break;') - ReturnedValue: - null - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'static IEnu ... }') - Left: - IParameterReferenceOperation: s (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'static IEnu ... }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'static IEnu ... }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'static IEnu ... }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'static IEnu ... }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""s"", IsImplicit) (Syntax: 'static IEnu ... }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestIOp_NullCheckedEmptyIteratorReturningIEnumerator() - { - var source = @" -using System.Collections.Generic; -class C -{ - public static void Main() { } - static IEnumerator GetChars(string s!!) - { - yield break; - } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'static IEnu ... }') - BlockBody: - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') - IReturnOperation (OperationKind.YieldBreak, Type: null) (Syntax: 'yield break;') - ReturnedValue: - null - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'static IEnu ... }') - Left: - IParameterReferenceOperation: s (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'static IEnu ... }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'static IEnu ... }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'static IEnu ... }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'static IEnu ... }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""s"", IsImplicit) (Syntax: 'static IEnu ... }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestNullCheckedLambdaWithMissingType() - { - var source = -@" -using System; -class Program -{ - public static void Main() - { - Func func = x!! => x; - } -} - -"; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - comp.MakeMemberMissing(WellKnownMember.System_ArgumentNullException__ctorString); - comp.MakeTypeMissing(WellKnownType.System_ArgumentNullException); - comp.VerifyDiagnostics( - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.ArgumentNullException", ".ctor").WithLocation(7, 37)); - var tree = comp.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - comp.VerifyOperationTree(node1, expectedOperationTree: @" -IMethodBodyOperation (OperationKind.MethodBody, Type: null, IsInvalid) (Syntax: 'public stat ... }') - BlockBody: - IBlockOperation (1 statements, 1 locals) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }') - Locals: Local_1: System.Func func - IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid) (Syntax: 'Func x;') - IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'Func x') - Declarators: - IVariableDeclaratorOperation (Symbol: System.Func func) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 'func = x!! => x') - Initializer: - IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= x!! => x') - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsInvalid, IsImplicit) (Syntax: 'x!! => x') - Target: - IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null, IsInvalid) (Syntax: 'x!! => x') - IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'x') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x') - ReturnedValue: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x') - Initializer: - null - ExpressionBody: - null"); - VerifyFlowGraph(comp, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} -{ - Locals: [System.Func func] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Func, IsInvalid, IsImplicit) (Syntax: 'func = x!! => x') - Left: - ILocalReferenceOperation: func (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Func, IsInvalid, IsImplicit) (Syntax: 'func = x!! => x') - Right: - IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsInvalid, IsImplicit) (Syntax: 'x!! => x') - Target: - IFlowAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.FlowAnonymousFunction, Type: null, IsInvalid) (Syntax: 'x!! => x') - { - Block[B0#A0] - Entry - Statements (0) - Next (Regular) Block[B1#A0] - Block[B1#A0] - Block - Predecessors: [B0#A0] - Statements (0) - Jump if False (Regular) to Block[B3#A0] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsInvalid, IsImplicit) (Syntax: 'x!! => x') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsInvalid, IsImplicit) (Syntax: 'x!! => x') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsInvalid, IsImplicit) (Syntax: 'x!! => x') - Next (Regular) Block[B2#A0] - Block[B2#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Throw) Block[null] - IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid, IsImplicit) (Syntax: 'x!! => x') - Children(1): - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsInvalid, IsImplicit) (Syntax: 'x!! => x') - Block[B3#A0] - Block - Predecessors: [B1#A0] - Statements (0) - Next (Return) Block[B4#A0] - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String) (Syntax: 'x') - Block[B4#A0] - Exit - Predecessors: [B3#A0] - Statements (0) - } - Next (Regular) Block[B2] - Leaving: {R1} -} -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestNullCheckedLocalFunctionWithMissingType() - { - var source = -@" -class Program -{ - public static void Main() - { - M(""ok""); - void M(string x!!) { } - } -}"; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - comp.MakeMemberMissing(WellKnownMember.System_ArgumentNullException__ctorString); - comp.MakeTypeMissing(WellKnownType.System_ArgumentNullException); - comp.VerifyDiagnostics( - // (7,23): error CS0656: Missing compiler required member 'System.ArgumentNullException..ctor' - // void M(string x!!) { } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.ArgumentNullException", ".ctor").WithLocation(7, 23)); - var tree = comp.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - var node2 = tree.GetRoot().DescendantNodes().OfType().Single(); - comp.VerifyOperationTree(node1, expectedOperationTree: @" - ILocalFunctionOperation (Symbol: void M(System.String x)) (OperationKind.LocalFunction, Type: null, IsInvalid) (Syntax: 'void M(string x!!) { }') - IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: '{ }') - ReturnedValue: - null"); - VerifyFlowGraph(comp, node2, @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} -{ - Methods: [void M(System.String x)] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'M(""ok"");') - Expression: - IInvocationOperation (void M(System.String x)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'M(""ok"")') - Instance Receiver: - null - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: '""ok""') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""ok"") (Syntax: '""ok""') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Next (Regular) Block[B2] - Leaving: {R1} - - { void M(System.String x) - - Block[B0#0R1] - Entry - Statements (0) - Next (Regular) Block[B1#0R1] - Block[B1#0R1] - Block - Predecessors: [B0#0R1] - Statements (0) - Jump if False (Regular) to Block[B3#0R1] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsInvalid, IsImplicit) (Syntax: 'void M(string x!!) { }') - Left: - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.String, IsInvalid, IsImplicit) (Syntax: 'void M(string x!!) { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsInvalid, IsImplicit) (Syntax: 'void M(string x!!) { }') - Next (Regular) Block[B2#0R1] - Block[B2#0R1] - Block - Predecessors: [B1#0R1] - Statements (0) - Next (Throw) Block[null] - IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid, IsImplicit) (Syntax: 'void M(string x!!) { }') - Children(1): - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsInvalid, IsImplicit) (Syntax: 'void M(string x!!) { }') - Block[B3#0R1] - Exit - Predecessors: [B1#0R1] - Statements (0) - } -} -Block[B2] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/58335: MakeMemberMissing doesn't work as expected with our method of obtaining Nullable.HasValue in this scenario")] - public void TestNullCheckedMethodWithMissingHasValue() - { - var source = -@" -class Program -{ - public void Method(int? x!!) { } -}"; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - comp.MakeMemberMissing(SpecialMember.System_Nullable_T_get_HasValue); - comp.VerifyDiagnostics( - // (4,29): warning CS8721: Nullable value type 'int?' is null-checked and will throw if null. - // public void Method(int? x!!) { } - Diagnostic(ErrorCode.WRN_NullCheckingOnNullableType, "x").WithArguments("int?").WithLocation(4, 29)); - var tree = comp.SyntaxTrees.Single(); - var node = tree.GetRoot().DescendantNodes().OfType().Single(); - comp.VerifyOperationTree(node, expectedOperationTree: @" - IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'public void ... t? x!!) { }') - BlockBody: - IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - ExpressionBody: - null"); - VerifyFlowGraph(comp, node, @" - Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if True (Regular) to Block[B3] - IInvalidOperation (OperationKind.Invalid, Type: System.Boolean, IsImplicit) (Syntax: 'public void ... t? x!!) { }') - Children(1): - IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32?, IsImplicit) (Syntax: 'public void ... t? x!!) { }') - Next (Regular) Block[B2] - Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public void ... t? x!!) { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public void ... t? x!!) { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""x"", IsImplicit) (Syntax: 'public void ... t? x!!) { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Block[B3] - Exit - Predecessors: [B1] - Statements (0)"); - } - - [Fact] - public void TestNoNullChecksInBlockOperation() - { - // https://github.com/dotnet/roslyn/issues/58320 - var source = @" -public class C -{ - public void M(string input!!) - /**/{ }/**/ -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().Single(); - - compilation.VerifyOperationTree(node1, expectedOperationTree: @" -IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') -"); - var output = @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public void ... */{ }') - Left: - IParameterReferenceOperation: input (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public void ... */{ }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public void ... */{ }') - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public void ... */{ }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public void ... */{ }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""input"", IsImplicit) (Syntax: 'public void ... */{ }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -Block[B3] - Exit - Predecessors: [B1] - Statements (0)"; - VerifyFlowGraphAndDiagnosticsForTest(compilation, expectedFlowGraph: output, DiagnosticDescription.None); - } - - [Fact] - public void TestNullCheckedBaseCallOrdering() - { - var source = @" -public class B -{ - public B(string x) { } -} -public class C : B -{ - public C(string param!!) : base(param ?? """") { } -}"; - var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - - compilation.VerifyDiagnostics(); - - var tree = compilation.SyntaxTrees.Single(); - var node1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); - compilation.VerifyOperationTree(node1, expectedOperationTree: @" -IConstructorBodyOperation (OperationKind.ConstructorBody, Type: null) (Syntax: 'public C(st ... ?? """") { }') - Initializer: - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: ': base(param ?? """")') - Expression: - IInvocationOperation ( B..ctor(System.String x)) (OperationKind.Invocation, Type: System.Void) (Syntax: ': base(param ?? """")') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: ': base(param ?? """")') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: 'param ?? """"') - ICoalesceOperation (OperationKind.Coalesce, Type: System.String) (Syntax: 'param ?? """"') - Expression: - IParameterReferenceOperation: param (OperationKind.ParameterReference, Type: System.String) (Syntax: 'param') - ValueConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - (Identity) - WhenNull: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: """") (Syntax: '""""') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - BlockBody: - IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ }') - ExpressionBody: - null"); - - VerifyFlowGraph(compilation, node1, expectedFlowGraph: @" -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] -Block[B1] - Block - Predecessors: [B0] - Statements (0) - Jump if False (Regular) to Block[B3] - IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean, IsImplicit) (Syntax: 'public C(st ... ?? """") { }') - Left: - IParameterReferenceOperation: param (OperationKind.ParameterReference, Type: System.String, IsImplicit) (Syntax: 'public C(st ... ?? """") { }') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: null, IsImplicit) (Syntax: 'public C(st ... ?? """") { }') - Entering: {R1} - Next (Regular) Block[B2] -Block[B2] - Block - Predecessors: [B1] - Statements (0) - Next (Throw) Block[null] - IObjectCreationOperation (Constructor: System.ArgumentNullException..ctor(System.String paramName)) (OperationKind.ObjectCreation, Type: System.ArgumentNullException, IsImplicit) (Syntax: 'public C(st ... ?? """") { }') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: paramName) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'public C(st ... ?? """") { }') - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: ""param"", IsImplicit) (Syntax: 'public C(st ... ?? """") { }') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null -.locals {R1} -{ - CaptureIds: [0] [2] - Block[B3] - Block - Predecessors: [B1] - Statements (1) - IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: ': base(param ?? """")') - Value: - IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: ': base(param ?? """")') - Next (Regular) Block[B4] - Entering: {R2} - .locals {R2} - { - CaptureIds: [1] - Block[B4] - Block - Predecessors: [B3] - Statements (1) - IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'param') - Value: - IParameterReferenceOperation: param (OperationKind.ParameterReference, Type: System.String) (Syntax: 'param') - Jump if True (Regular) to Block[B6] - IIsNullOperation (OperationKind.IsNull, Type: System.Boolean, IsImplicit) (Syntax: 'param') - Operand: - IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'param') - Leaving: {R2} - Next (Regular) Block[B5] - Block[B5] - Block - Predecessors: [B4] - Statements (1) - IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'param') - Value: - IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'param') - Next (Regular) Block[B7] - Leaving: {R2} - } - Block[B6] - Block - Predecessors: [B4] - Statements (1) - IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '""""') - Value: - ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: """") (Syntax: '""""') - Next (Regular) Block[B7] - Block[B7] - Block - Predecessors: [B5] [B6] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: ': base(param ?? """")') - Expression: - IInvocationOperation ( B..ctor(System.String x)) (OperationKind.Invocation, Type: System.Void) (Syntax: ': base(param ?? """")') - Instance Receiver: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: B, IsImplicit) (Syntax: ': base(param ?? """")') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: 'param ?? """"') - IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: System.String, IsImplicit) (Syntax: 'param ?? """"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Next (Regular) Block[B8] - Leaving: {R1} -} -Block[B8] - Exit - Predecessors: [B7] Statements (0)"); } } diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs index 89d8d0d468037..f8dde5edc9765 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs @@ -1004,7 +1004,7 @@ public void TestReportingDiagnosticWithBasicCompilerId() [Theory, WorkItem(7173, "https://github.com/dotnet/roslyn/issues/7173")] [CombinatorialData] - public void TestReportingDiagnosticWithInvalidLocation(AnalyzerWithInvalidDiagnosticLocation.ActionKind actionKind) + public void TestReportingDiagnosticWithInvalidLocation(AnalyzerWithInvalidDiagnosticLocation.ActionKind actionKind, bool testInvalidAdditionalLocation) { var source1 = @"class C1 { void M() { int i = 0; i++; } }"; var source2 = @"class C2 { void M() { int i = 0; i++; } }"; @@ -1017,7 +1017,7 @@ public void TestReportingDiagnosticWithInvalidLocation(AnalyzerWithInvalidDiagno compilation.VerifyDiagnostics(); - var analyzer = new AnalyzerWithInvalidDiagnosticLocation(treeInAnotherCompilation, actionKind); + var analyzer = new AnalyzerWithInvalidDiagnosticLocation(treeInAnotherCompilation, actionKind, testInvalidAdditionalLocation); var analyzers = new DiagnosticAnalyzer[] { analyzer }; Exception analyzerException = null; @@ -1502,7 +1502,7 @@ private class NestedGeneratedCode{0} {{ }} generatedFileNames.Add(myGeneratedFileTrueName); tree = CSharpSyntaxTree.ParseText(string.Format(source, treeNum++), path: myGeneratedFileTrueName); builder.Add(tree); - var analyzerConfigOptions = new CompilerAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("generated_code", "true")); + var analyzerConfigOptions = new DictionaryAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("generated_code", "true")); analyzerConfigOptionsPerTreeBuilder.Add(tree, analyzerConfigOptions); // (2) "generated_code = TRUE" (case insensitive) @@ -1510,22 +1510,22 @@ private class NestedGeneratedCode{0} {{ }} generatedFileNames.Add(myGeneratedFileCaseInsensitiveTrueName); tree = CSharpSyntaxTree.ParseText(string.Format(source, treeNum++), path: myGeneratedFileCaseInsensitiveTrueName); builder.Add(tree); - analyzerConfigOptions = new CompilerAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("generated_code", "TRUE")); + analyzerConfigOptions = new DictionaryAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("generated_code", "TRUE")); analyzerConfigOptionsPerTreeBuilder.Add(tree, analyzerConfigOptions); // (3) "generated_code = false" tree = CSharpSyntaxTree.ParseText(string.Format(source, treeNum++), path: "MyGeneratedFileFalse.cs"); builder.Add(tree); - analyzerConfigOptions = new CompilerAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("generated_code", "false")); + analyzerConfigOptions = new DictionaryAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("generated_code", "false")); analyzerConfigOptionsPerTreeBuilder.Add(tree, analyzerConfigOptions); // (4) "generated_code = auto" tree = CSharpSyntaxTree.ParseText(string.Format(source, treeNum++), path: "MyGeneratedFileAuto.cs"); builder.Add(tree); - analyzerConfigOptions = new CompilerAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("generated_code", "auto")); + analyzerConfigOptions = new DictionaryAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("generated_code", "auto")); analyzerConfigOptionsPerTreeBuilder.Add(tree, analyzerConfigOptions); - var analyzerConfigOptionsProvider = new CompilerAnalyzerConfigOptionsProvider(analyzerConfigOptionsPerTreeBuilder.ToImmutable(), CompilerAnalyzerConfigOptions.Empty); + var analyzerConfigOptionsProvider = new CompilerAnalyzerConfigOptionsProvider(analyzerConfigOptionsPerTreeBuilder.ToImmutable(), DictionaryAnalyzerConfigOptions.Empty); var analyzerOptions = new AnalyzerOptions(additionalFiles: ImmutableArray.Empty, analyzerConfigOptionsProvider); // Verify no compiler diagnostics. @@ -3762,5 +3762,43 @@ public void VerifyCachedModel(SyntaxTree tree, SemanticModel model) Assert.Same(model, _cache[tree]); } } + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class RecordDeclarationAnalyzer : DiagnosticAnalyzer + { + public const string DiagnosticId = "MyDiagnostic"; + internal const string Title = "MyDiagnostic"; + internal const string MessageFormat = "MyDiagnostic"; + internal const string Category = "Category"; + + internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } } + + public override void Initialize(AnalysisContext context) + { + context.RegisterSyntaxNodeAction(AnalyzeRecordDeclaration, SyntaxKind.RecordDeclaration); + } + + private static void AnalyzeRecordDeclaration(SyntaxNodeAnalysisContext context) + { + var recordDeclaration = (RecordDeclarationSyntax)context.Node; + var diagnostic = CodeAnalysis.Diagnostic.Create(Rule, recordDeclaration.GetLocation()); + context.ReportDiagnostic(diagnostic); + } + } + + [Fact, WorkItem(53136, "https://github.com/dotnet/roslyn/issues/53136")] + public void TestNoDuplicateCallbacksForRecordDeclaration() + { + string source = @" +public record A(int X, int Y);"; + var analyzers = new DiagnosticAnalyzer[] { new RecordDeclarationAnalyzer() }; + + CreateCompilation(new[] { source, IsExternalInitTypeDefinition }) + .VerifyDiagnostics() + .VerifyAnalyzerDiagnostics(analyzers, null, null, + Diagnostic("MyDiagnostic", @"public record A(int X, int Y);").WithLocation(2, 1)); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/GetDiagnosticsTests.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/GetDiagnosticsTests.cs index 3f5ef60224856..e9cf8527c29de 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/GetDiagnosticsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/GetDiagnosticsTests.cs @@ -493,10 +493,10 @@ void M() verifyDiagnostics(analyzerDiagnostics); // Verify CS0168 reported by CSharpCompilerDiagnosticAnalyzer is not affected by "dotnet_analyzer_diagnostic = none" - var analyzerConfigOptions = new CompilerAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("dotnet_analyzer_diagnostic.severity", "none")); + var analyzerConfigOptions = new DictionaryAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("dotnet_analyzer_diagnostic.severity", "none")); var analyzerConfigOptionsProvider = new CompilerAnalyzerConfigOptionsProvider( ImmutableDictionary.Empty.Add(compilation.SyntaxTrees.Single(), analyzerConfigOptions), - CompilerAnalyzerConfigOptions.Empty); + DictionaryAnalyzerConfigOptions.Empty); var analyzerOptions = new AnalyzerOptions(ImmutableArray.Empty, analyzerConfigOptionsProvider); compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, analyzerOptions); analyzerDiagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(); @@ -539,10 +539,10 @@ static async Task verifyDiagnosticsAsync(Compilation compilation, DiagnosticAnal AnalyzerOptions analyzerOptions; if (options.HasValue) { - var analyzerConfigOptions = new CompilerAnalyzerConfigOptions(ImmutableDictionary.Empty.Add(options.Value.key, options.Value.value)); + var analyzerConfigOptions = new DictionaryAnalyzerConfigOptions(ImmutableDictionary.Empty.Add(options.Value.key, options.Value.value)); var analyzerConfigOptionsProvider = new CompilerAnalyzerConfigOptionsProvider( ImmutableDictionary.Empty.Add(compilation.SyntaxTrees.Single(), analyzerConfigOptions), - CompilerAnalyzerConfigOptions.Empty); + DictionaryAnalyzerConfigOptions.Empty); analyzerOptions = new AnalyzerOptions(ImmutableArray.Empty, analyzerConfigOptionsProvider); } else diff --git a/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs b/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs index 552d59dbf7a25..e2423f12d9a39 100644 --- a/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs @@ -8032,6 +8032,59 @@ static void Main() Assert.Equal("px", GetSymbolNamesJoined(analysis.WrittenOutside)); } + [WorkItem(57428, "https://github.com/dotnet/roslyn/issues/57428")] + [Fact] + public void AttributeArgumentWithLambdaBody_01() + { + var source = +@"using System.Runtime.InteropServices; +class Program +{ + static void F([DefaultParameterValue(() => { return 0; })] object obj) + { + } +}"; + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics( + // (4,42): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // static void F([DefaultParameterValue(() => { return 0; })] object obj) + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "() => { return 0; }").WithLocation(4, 42)); + + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var expr = tree.GetRoot().DescendantNodes().OfType().Single(); + var analysis = model.AnalyzeDataFlow(expr); + Assert.False(analysis.Succeeded); + } + + [Fact] + public void AttributeArgumentWithLambdaBody_02() + { + var source = +@"using System; +class A : Attribute +{ + internal A(object o) { } +} +class Program +{ + static void F([A(() => { return 0; })] object obj) + { + } +}"; + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics( + // (8,22): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // static void F([A(() => { return 0; })] object obj) + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "() => { return 0; }").WithLocation(8, 22)); + + var tree = compilation.SyntaxTrees[0]; + var model = compilation.GetSemanticModel(tree); + var expr = tree.GetRoot().DescendantNodes().OfType().Single(); + var analysis = model.AnalyzeDataFlow(expr); + Assert.False(analysis.Succeeded); + } + #endregion #region "Used Local Functions" @@ -8928,6 +8981,55 @@ public void TestInterpolatedStringHandlers(bool validityParameter, bool useBoolR CustomHandler c = $""{i1 = 1}{i2 = 2}""; /**/ +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount" + (validityParameter ? ", out bool success" : "") + @") + { +" + (validityParameter ? "success = true;" : "") + @" + } + + public " + (useBoolReturns ? "bool" : "void") + @" AppendFormatted(int i) => throw null; +} +" + InterpolatedStringHandlerAttribute; + + var (controlFlowAnalysisResults, dataFlowAnalysisResults) = CompileAndAnalyzeControlAndDataFlowStatements(code); + Assert.Equal(0, controlFlowAnalysisResults.EntryPoints.Count()); + Assert.Equal(0, controlFlowAnalysisResults.ExitPoints.Count()); + Assert.True(controlFlowAnalysisResults.EndPointIsReachable); + Assert.Equal("c", GetSymbolNamesJoined(dataFlowAnalysisResults.VariablesDeclared)); + Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsIn)); + Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.DataFlowsOut)); + Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnEntry)); + + var definitelyAssigned = (validityParameter, useBoolReturns) switch + { + (true, _) => "c", + (_, true) => "i1, c", + (_, false) => "i1, i2, c" + }; + + Assert.Equal(definitelyAssigned + ", args", GetSymbolNamesJoined(dataFlowAnalysisResults.DefinitelyAssignedOnExit)); + Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadInside)); + Assert.Null(GetSymbolNamesJoined(dataFlowAnalysisResults.ReadOutside)); + Assert.Equal("i1, i2, c", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenInside)); + Assert.Equal("args", GetSymbolNamesJoined(dataFlowAnalysisResults.WrittenOutside)); + } + + [Theory] + [CombinatorialData] + public void TestRawInterpolatedStringHandlers(bool validityParameter, bool useBoolReturns) + { + var code = @" +using System.Runtime.CompilerServices; + +int i1; +int i2; + +/**/ +CustomHandler c = $""""""{i1 = 1}{i2 = 2}""""""; +/**/ + [InterpolatedStringHandler] public struct CustomHandler { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs index 7b23e2a17ae05..80447d7cba237 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; @@ -189,7 +190,7 @@ .locals init (int V_0) //i IL_0013: ret }"; - var verifier = CompileAndVerify(source: text, expectedOutput: "System.Int32"); + var verifier = CompileAndVerify(source: text, expectedOutput: "System.Int32", verify: Verification.FailsILVerify); verifier.VerifyIL("C.Main", expectedIL); } @@ -357,7 +358,7 @@ .maxstack 1 IL_0008: ret }"; - var verifier = CompileAndVerify(source: text, expectedOutput: "System.String"); + var verifier = CompileAndVerify(source: text, expectedOutput: "System.String", verify: Verification.FailsILVerify); verifier.VerifyIL("C.M", expectedIL); } @@ -672,7 +673,7 @@ .maxstack 2 IL_000c: ret }"; - var verifier = CompileAndVerify(source: text, expectedOutput: "1123"); + var verifier = CompileAndVerify(source: text, expectedOutput: "1123", verify: Verification.FailsILVerify); verifier.VerifyIL("C.Get", expectedGetIL); verifier.VerifyIL("C.Set", expectedSetIL); verifier.VerifyIL("C.Ref", expectedRefIL); @@ -794,7 +795,7 @@ .locals init (int V_0, //x 42 333 0 -42"); +42", verify: Verification.FailsILVerify); verifier.VerifyIL("Program.Main", expectedGetIL); } @@ -902,7 +903,7 @@ static void Main() } }"; - var verifier = CompileAndVerify(source: text, expectedOutput: "4242"); + var verifier = CompileAndVerify(source: text, expectedOutput: "4242", verify: Verification.FailsILVerify); verifier.VerifyIL("C.Main", @" { // Code size 72 (0x48) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs index 32280b50301e3..48eaebdb8fa49 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BetterCandidates.cs @@ -862,7 +862,8 @@ public class ExtensionAttribute : System.Attribute {} ); var compilation = CreateCompilationWithBetterCandidates(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( ); - CompileAndVerify(compilation, expectedOutput: "2"); + // ILVerify: Unrecognized arguments for delegate .ctor. + CompileAndVerify(compilation, verify: Verification.FailsILVerify, expectedOutput: "2"); } // Test suggested by @VSadov diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index fbf712806045b..f7a27e78372fa 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -1587,11 +1587,12 @@ public static void M(MyResult r) var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe); compilation.VerifyDiagnostics(); - CompileAndVerify(compilation, expectedOutput: "3"); + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + CompileAndVerify(compilation, verify: Verification.FailsILVerify, expectedOutput: "3"); compilation = CreateCompilation(source, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); - CompileAndVerify(compilation, expectedOutput: "3"); + CompileAndVerify(compilation, verify: Verification.FailsILVerify, expectedOutput: "3"); } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAwaitTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAwaitTests.cs index b6d0a3a64f4aa..a975327fa6590 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAwaitTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAwaitTests.cs @@ -2836,7 +2836,8 @@ static void Main() // warning CS1685: The predefined type 'ExtensionAttribute' is defined in multiple assemblies in the global alias; using definition from 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' Diagnostic(ErrorCode.WRN_MultiplePredefTypes).WithArguments("System.Runtime.CompilerServices.ExtensionAttribute", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(1, 1)); - var compiled = CompileAndVerify(comp, expectedOutput: "dynamic42", verify: Verification.Fails); + // PEVerify: Cannot change initonly field outside its .ctor. + var compiled = CompileAndVerify(comp, expectedOutput: "dynamic42", verify: Verification.FailsPEVerify); compiled.VerifyIL("MyAwaiter.OnCompleted(System.Action)", @" { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ConstantTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ConstantTests.cs index 6bbabbc897fcb..74957dc8f8168 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ConstantTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ConstantTests.cs @@ -3541,6 +3541,33 @@ void M() Assert.Equal(expected, actual); } + [Fact] + public void ConstantRawInterpolatedStringsSimple() + { + string source = @" +class C +{ + void M() + { + const string S1 = $""""""Testing""""""; + const string S2 = $""""""{""Level 5""} {""Number 3""}""""""; + const string S3 = $""""""{$""{""Spinning Top""}""}""""""; + const string F1 = $""""""{S1}""""""; + const string F2 = $""""""{F1} the {S2}""""""; + } +}"; + var actual = ParseAndGetConstantFoldingSteps(source); + + var expected = +@"$""""""Testing"""""" --> Testing +$""""""{""Level 5""} {""Number 3""}"""""" --> Level 5 Number 3 +$""""""{$""{""Spinning Top""}""}"""""" --> Spinning Top +$""{""Spinning Top""}"" --> Spinning Top +$""""""{S1}"""""" --> Testing +$""""""{F1} the {S2}"""""" --> Testing the Level 5 Number 3"; + Assert.Equal(expected, actual); + } + [Fact] public void ConstantInterpolatedStringsContinued() { @@ -3582,6 +3609,47 @@ void M(string S1 = $""Testing"", Namae n = null) comp.VerifyDiagnostics(); } + [Fact] + public void ConstantRawInterpolatedStringsContinued() + { + string source = @" +public class A : System.Attribute +{ + private string name; + + public A(string name) + { + this.name = name; + } +} + +[A($""ITEM"")] +class C +{ + const string S0 = $""""""Faaaaaaaaaaaaaaaaaaaaaaaaall""""""; + + class Namae + { + public string X { get; } + } + + void M(string S1 = $""""""Testing"""""", Namae n = null) + { + if (n is Namae { X : $""""""ConstantInterpolatedString""""""}){ + switch(S1){ + case $""""""Level 5"""""": + break; + case $""""""Radio Noise"""""": + goto case $""""""Level 5""""""; + } + } + S1 = S0; + } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + } + [Fact] public void ConstantInterpolatedStringsError() { @@ -3618,6 +3686,42 @@ void M(string ParamDefault = ""Academy City"") Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""{I1} the {S1}""").WithArguments("F2").WithLocation(12, 27)); } + [Fact] + public void ConstantRawInterpolatedStringsError() + { + string source = @" +class C +{ + void M(string ParamDefault = """"""Academy City"""""") + { + const string S1 = $""""""Testing""""""; + const string S2 = $""""""{""Level 5""} {3}""""""; + const string S3 = $""""""{$""{""Spinning Top"", 10}""}""""""; + const string S4 = $""""""{ParamDefault}""""""; + const int I1 = 0; + const string F1 = $""""""{I1}""""""; + const string F2 = $""""""{I1} the {S1}""""""; + } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (7,27): error CS0133: The expression being assigned to 'S2' must be constant + // const string S2 = $"""{"Level 5"} {3}"""; + Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{""Level 5""} {3}""""""").WithArguments("S2").WithLocation(7, 27), + // (8,27): error CS0133: The expression being assigned to 'S3' must be constant + // const string S3 = $"""{$"{"Spinning Top", 10}"}"""; + Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{$""{""Spinning Top"", 10}""}""""""").WithArguments("S3").WithLocation(8, 27), + // (9,27): error CS0133: The expression being assigned to 'S4' must be constant + // const string S4 = $"""{ParamDefault}"""; + Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{ParamDefault}""""""").WithArguments("S4").WithLocation(9, 27), + // (11,27): error CS0133: The expression being assigned to 'F1' must be constant + // const string F1 = $"""{I1}"""; + Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{I1}""""""").WithArguments("F1").WithLocation(11, 27), + // (12,27): error CS0133: The expression being assigned to 'F2' must be constant + // const string F2 = $"""{I1} the {S1}"""; + Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{I1} the {S1}""""""").WithArguments("F2").WithLocation(12, 27)); + } + [Fact] public void ConstantInterpolatedStringsHybrid() { @@ -3642,6 +3746,30 @@ void M() Assert.Equal(expected, actual); } + [Fact] + public void ConstantRawInterpolatedStringsHybrid() + { + string source = @" +class C +{ + void M() + { + const string S1 = $""""""Number """""" + ""3""; + const string S2 = $""""""{""Level 5""} """""" + S1; + const string F1 = $""""""{S1}""""""; + } +}"; + var actual = ParseAndGetConstantFoldingSteps(source); + + var expected = +@"$""""""Number """""" + ""3"" --> Number 3 +$""""""Number """""" --> Number +$""""""{""Level 5""} """""" + S1 --> Level 5 Number 3 +$""""""{""Level 5""} """""" --> Level 5 +$""""""{S1}"""""" --> Number 3"; + Assert.Equal(expected, actual); + } + [Fact] public void ConstantInterpolatedStringsHybridError() { @@ -3670,6 +3798,34 @@ void M() Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""{S1}""").WithArguments("F1").WithLocation(10, 27)); } + [Fact] + public void ConstantRawInterpolatedStringsHybridError() + { + string source = @" +class C +{ + void M() + { + + string NC1 = """"""Teleporter""""""; + const string S1 = ""The"" + $""""""Number {3}"""""" + ""Level 5""; + const string S2 = $""""""Level 4 """""" + NC1; + const string F1 = $""""""{S1}""""""; + } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (8,27): error CS0133: The expression being assigned to 'S1' must be constant + // const string S1 = "The" + $"""Number {3}""" + "Level 5"; + Diagnostic(ErrorCode.ERR_NotConstantExpression, @"""The"" + $""""""Number {3}"""""" + ""Level 5""").WithArguments("S1").WithLocation(8, 27), + // (9,27): error CS0133: The expression being assigned to 'S2' must be constant + // const string S2 = $"""Level 4 """ + NC1; + Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""Level 4 """""" + NC1").WithArguments("S2").WithLocation(9, 27), + // (10,27): error CS0133: The expression being assigned to 'F1' must be constant + // const string F1 = $"""{S1}"""; + Diagnostic(ErrorCode.ERR_NotConstantExpression, @"$""""""{S1}""""""").WithArguments("F1").WithLocation(10, 27)); + } + [Fact] public void ConstantInterpolatedStringsVersionError() { @@ -3805,6 +3961,27 @@ static void Main() Assert.Equal(string.Empty, module.GlobalNamespace.GetTypeMember("C").GetField("s").ConstantValue); }); } + + [Fact] + public void EmptyConstRawInterpolatedString() + { + CompileAndVerify(@" +public class C +{ + public const string s = $"""""" + +""""""; + + static void Main() + { + System.Console.WriteLine(s); + } +} +", parseOptions: TestOptions.RegularPreview, expectedOutput: "", symbolValidator: module => + { + Assert.Equal(string.Empty, module.GlobalNamespace.GetTypeMember("C").GetField("s").ConstantValue); + }); + } } internal sealed class BoundTreeSequencer : BoundTreeWalkerWithStackGuard diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs index 9b395c870f7be..40ee9a8a34913 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs @@ -6445,5 +6445,91 @@ class C2 Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "(i, c) = new C2()").WithArguments("C.implicit operator bool(C)", "Obsolete error").WithLocation(6, 1) ); } + + [Fact, WorkItem(58472, "https://github.com/dotnet/roslyn/issues/58472")] + public void DeconstructionIntoImplicitIndexers() + { + var source = @" +var x = new int[1]; +C.M(x); + +var y = new int[1]; +C.M2(y); + +System.Console.Write((x[^1], y[^1])); + +class C +{ + public static void M(T[] a) + { + (a[0], a[^1]) = (default, default); + } + + public static void M2(int[] a) + { + (a[0], a[^1]) = (default, default); + } +} +"; + + var comp = CreateCompilationWithIndex(source); + // No IndexOutOfRangeException thrown + var verifier = CompileAndVerify(comp, expectedOutput: "(0, 0)"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.M(T[])", @" +{ + // Code size 41 (0x29) + .maxstack 3 + .locals init (T[] V_0, + int V_1, + T V_2) + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: dup + IL_0003: stloc.0 + IL_0004: ldlen + IL_0005: conv.i4 + IL_0006: ldc.i4.1 + IL_0007: sub + IL_0008: stloc.1 + IL_0009: ldc.i4.0 + IL_000a: ldloca.s V_2 + IL_000c: initobj ""T"" + IL_0012: ldloc.2 + IL_0013: stelem ""T"" + IL_0018: ldloc.0 + IL_0019: ldloc.1 + IL_001a: ldloca.s V_2 + IL_001c: initobj ""T"" + IL_0022: ldloc.2 + IL_0023: stelem ""T"" + IL_0028: ret +} +"); + verifier.VerifyIL("C.M2", @" +{ + // Code size 25 (0x19) + .maxstack 3 + .locals init (int& V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: ldelema ""int"" + IL_0007: stloc.0 + IL_0008: ldarg.0 + IL_0009: dup + IL_000a: ldlen + IL_000b: conv.i4 + IL_000c: ldc.i4.1 + IL_000d: sub + IL_000e: ldelema ""int"" + IL_0013: ldloc.0 + IL_0014: ldc.i4.0 + IL_0015: stind.i4 + IL_0016: ldc.i4.0 + IL_0017: stind.i4 + IL_0018: ret +} +"); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 3db35f37d6dfc..a8145b8774058 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -1298,7 +1298,8 @@ static class B var comp = CreateCompilation(new[] { source, s_utils }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe); if (expectedDiagnostics is null) { - CompileAndVerify(comp, expectedOutput: $"{expectedMethod}: {expectedType}"); + // ILVerify: Unrecognized arguments for delegate .ctor. + CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: $"{expectedMethod}: {expectedType}"); } else { @@ -1392,7 +1393,8 @@ static class B var comp = CreateCompilation(new[] { source, s_utils }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe); if (expectedDiagnostics is null) { - CompileAndVerify(comp, expectedOutput: $"{expectedMethod}: {expectedType}"); + // ILVerify: Unrecognized arguments for delegate .ctor. + CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: $"{expectedMethod}: {expectedType}"); } else { @@ -1767,7 +1769,8 @@ static void Main() } }"; var comp = CreateCompilation(new[] { source, s_utils }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe); - CompileAndVerify(comp, expectedOutput: "System.Action, System.Action"); + // ILVerify: Unrecognized arguments for delegate .ctor. + CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: "System.Action, System.Action"); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -1946,24 +1949,27 @@ static void Main() public void InvalidTypeArguments() { var source = -@"unsafe class Program +@"using System; +unsafe class Program { - static int* F() => throw null; + static int* F() { Console.WriteLine(nameof(F)); return (int*)0; } static void Main() { - System.Delegate d; - d = F; - d = (int x, int* y) => { }; + var d1 = F; + var d2 = (int x, int* y) => { Console.WriteLine((x, (int)y)); }; + d1.Invoke(); + d2.Invoke(1, (int*)2); + Report(d1); + Report(d2); } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview, options: TestOptions.UnsafeReleaseExe); - comp.VerifyDiagnostics( - // (7,13): error CS8917: The delegate type could not be inferred. - // d = F; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "F").WithLocation(7, 13), - // (8,13): error CS8917: The delegate type could not be inferred. - // d = (int x, int* y) => { }; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(int x, int* y) => { }").WithLocation(8, 13)); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"F +(1, 2) +<>f__AnonymousDelegate0 +<>f__AnonymousDelegate1 +"); } [Fact] @@ -2722,7 +2728,7 @@ static void Main() } [Fact] - public void SystemIntPtr_Missing() + public void SystemIntPtr_Missing_01() { var sourceA = @"namespace System @@ -2757,6 +2763,42 @@ static void Main() Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "(ref int i) => i").WithArguments("System.IntPtr").WithLocation(6, 13)); } + [Fact] + public void SystemIntPtr_Missing_02() + { + var sourceA = +@"namespace System +{ + public class Object { } + public abstract class ValueType { } + public class String { } + public class Type { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public abstract class Delegate { } + public abstract class MulticastDelegate : Delegate { } +}"; + var sourceB = +@"class Program +{ + static unsafe void Main() + { + System.Delegate d; + d = (int* p) => p; + } +}"; + var comp = CreateEmptyCompilation(new[] { sourceA, sourceB }, options: TestOptions.UnsafeReleaseExe); + comp.VerifyEmitDiagnostics( + // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. + Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1), + // error CS0518: Predefined type 'System.IntPtr' is not defined or imported + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.IntPtr").WithLocation(1, 1), + // (6,13): error CS0518: Predefined type 'System.IntPtr' is not defined or imported + // d = (int* p) => p; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "(int* p) => p").WithArguments("System.IntPtr").WithLocation(6, 13)); + } + [Fact] public void SystemMulticastDelegate_Missing() { @@ -6958,7 +7000,7 @@ static void Main() // var d3 = delegate () { }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "delegate () { }").WithArguments("inferred delegate type", "10.0").WithLocation(10, 18)); - comp = CreateCompilation(new[] { source, s_utils }, options: TestOptions.DebugExe); + comp = CreateCompilation(new[] { source, s_utils }, parseOptions: TestOptions.Regular10, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: @@ -7869,7 +7911,8 @@ static class E var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); - var verifier = CompileAndVerify(comp, expectedOutput: @"(41, 42)"); + // ILVerify: Unrecognized arguments for delegate .ctor. + var verifier = CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: @"(41, 42)"); verifier.VerifyIL("Program.M1", @"{ // Code size 20 (0x14) @@ -8060,7 +8103,7 @@ static void Main() static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; - var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: @@ -8281,7 +8324,7 @@ static void Main() static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; - var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: @@ -8356,31 +8399,40 @@ static void Main() public void SynthesizedDelegateTypes_11() { var source = -@"class Program +@"using System; +class Program { unsafe static void Main() { - var d1 = int* () => (int*)42; - var d2 = (int* p) => { }; - var d3 = delegate* () => default; - var d4 = (delegate* d) => { }; + var d1 = int* () => { Console.WriteLine(1); return (int*)42; }; + var d2 = (int* p) => { Console.WriteLine((int)p); }; + var d3 = delegate* () => { Console.WriteLine(3); return default; }; + var d4 = (delegate* d) => { Console.WriteLine((int)d); }; + d1.Invoke(); + d2.Invoke((int*)2); + d3.Invoke(); + d4.Invoke((delegate*)4); + Report(d1); + Report(d2); + Report(d3); + Report(d4); } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe); - comp.VerifyDiagnostics( - // (5,18): error CS8917: The delegate type could not be inferred. - // var d1 = int* () => (int*)42; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "int* () => (int*)42").WithLocation(5, 18), - // (6,18): error CS8917: The delegate type could not be inferred. - // var d2 = (int* p) => { }; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(int* p) => { }").WithLocation(6, 18), - // (7,18): error CS8917: The delegate type could not be inferred. - // var d3 = delegate* () => default; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "delegate* () => default").WithLocation(7, 18), - // (8,18): error CS8917: The delegate type could not be inferred. - // var d4 = (delegate* d) => { }; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(delegate* d) => { }").WithLocation(8, 18)); + comp.VerifyDiagnostics(); + + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: +@"1 +2 +3 +4 +<>f__AnonymousDelegate0 +<>f__AnonymousDelegate1 +<>f__AnonymousDelegate2 +<>f__AnonymousDelegate3 +"); } [WorkItem(55217, "https://github.com/dotnet/roslyn/issues/55217")] @@ -8396,19 +8448,21 @@ static void Main() var d1 = (TypedReference x) => { }; var d2 = (int x, RuntimeArgumentHandle y) => { }; var d3 = (ArgIterator x) => { }; + Report(d1); + Report(d2); + Report(d3); } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (6,18): error CS8917: The delegate type could not be inferred. - // var d1 = (TypedReference x) => { }; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(TypedReference x) => { }").WithLocation(6, 18), - // (7,18): error CS8917: The delegate type could not be inferred. - // var d2 = (int x, RuntimeArgumentHandle y) => { }; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(int x, RuntimeArgumentHandle y) => { }").WithLocation(7, 18), - // (8,18): error CS8917: The delegate type could not be inferred. - // var d3 = (ArgIterator x) => { }; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(ArgIterator x) => { }").WithLocation(8, 18)); + + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics(); + + CompileAndVerify(comp, expectedOutput: +@"<>f__AnonymousDelegate0 +<>f__AnonymousDelegate1 +<>f__AnonymousDelegate2 +"); } [WorkItem(55217, "https://github.com/dotnet/roslyn/issues/55217")] @@ -8416,25 +8470,34 @@ static void Main() public void SynthesizedDelegateTypes_13() { var source = -@"ref struct S { } +@"using System; +ref struct S { } class Program { - static void F1(int x, S y) { } - static S F2() => throw null; + static void F1(int x, S y) { Console.WriteLine(x); } + static S F2() { Console.WriteLine(typeof(T)); return default; } static void Main() { var d1 = F1; var d2 = F2; + d1.Invoke(0, default); + d2.Invoke(); + Report(d1); + Report(d2); } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; - var comp = CreateCompilation(source); - comp.VerifyDiagnostics( - // (8,18): error CS8917: The delegate type could not be inferred. - // var d1 = F1; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "F1").WithLocation(8, 18), - // (9,18): error CS8917: The delegate type could not be inferred. - // var d2 = F2; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "F2").WithLocation(9, 18)); + + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics(); + + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. { Offset = 24 } + CompileAndVerify(comp, expectedOutput: +@"0 +System.Object +<>f__AnonymousDelegate0 +<>f__AnonymousDelegate1 +", verify: Verification.FailsILVerify); } [Fact] @@ -8710,7 +8773,7 @@ static void Main() static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; - var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, validator: validator, expectedOutput: "D"); static void validator(PEAssembly assembly) @@ -8751,7 +8814,7 @@ static void Main() static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; - var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, validator: validator, expectedOutput: @"<>A{00000001}`2[System.Object,System.Object] D2 @@ -8852,6 +8915,703 @@ class B "); } + [Fact] + public void SynthesizedDelegateTypes_25() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Delegate d1 = A.F1(); + Delegate d2 = A.F2(); + Delegate d3 = B.F3(); + Delegate d4 = A.F2(); + Delegate d5 = B.F3(); + d1.DynamicInvoke(); + d2.DynamicInvoke(); + d3.DynamicInvoke(); + d4.DynamicInvoke(); + d5.DynamicInvoke(); + Report(d1); + Report(d2); + Report(d3); + Report(d4); + Report(d5); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +class A +{ + internal unsafe static Delegate F1() => int* () => { Console.WriteLine(nameof(F1)); return (int*)1; }; + internal unsafe static Delegate F2() => int* () => { Console.WriteLine((nameof(F2), typeof(T))); return (int*)2; }; +} +class B +{ + internal unsafe static Delegate F3() => int* () => { Console.WriteLine((nameof(F3), typeof(T))); return (int*)3; }; +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"F1 +(F2, System.Int32) +(F3, System.String) +(F2, System.String) +(F3, System.Int32) +<>f__AnonymousDelegate0 +<>f__AnonymousDelegate0 +<>f__AnonymousDelegate0 +<>f__AnonymousDelegate0 +<>f__AnonymousDelegate0 +"); + } + + [WorkItem(55217, "https://github.com/dotnet/roslyn/issues/55217")] + [Fact] + public void SynthesizedDelegateTypes_26() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Span s = stackalloc int[] { 1, 2, 3 }; + var d = (Span s) => { Console.WriteLine(s.Length); }; + d.Invoke(s); + Console.WriteLine(d.GetType()); + } +}"; + var comp = CreateCompilationWithSpan(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: +@"3 +<>f__AnonymousDelegate0 +"); + } + + [WorkItem(55217, "https://github.com/dotnet/roslyn/issues/55217")] + [Fact] + public void SynthesizedDelegateTypes_27() + { + var source = +@"#nullable enable +class Program +{ + unsafe static void Main() + { + object o = null; // 1 + var d = (int* p) => o; + d((int*)42).ToString(); // 2 + } +}"; + // Should report warning 2. + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe); + comp.VerifyDiagnostics( + // (6,20): warning CS8600: Converting null literal or possible null value to non-nullable type. + // object o = null; // 1 + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(6, 20)); + } + + [WorkItem(55217, "https://github.com/dotnet/roslyn/issues/55217")] + [Fact] + public void SynthesizedDelegateTypes_28() + { + var sourceA = +@"using System; +class A +{ + static void Main() + { + B.M(); + C.M(); + } + internal static void Report(Delegate d) => Console.WriteLine(d.GetType()); +}"; + var sourceB = +@"using System; +class B +{ + internal unsafe static void M() + { + int* x = (int*)42; + var d1 = (int y) => { Console.WriteLine((1, y)); return x; }; + var d2 = (ref int y) => { Console.WriteLine((2, y)); return x; }; + var d3 = (out int y) => { Console.WriteLine(3); y = 0; return x; }; + var d4 = (in int y) => { Console.WriteLine((4, y)); return x; }; + int i = 42; + d1.Invoke(i); + d2.Invoke(ref i); + d3.Invoke(out i); + d4.Invoke(in i); + A.Report(d1); + A.Report(d2); + A.Report(d3); + A.Report(d4); + } +}"; + var sourceC = +@"using System; +class C +{ + internal unsafe static void M() + { + int* p = (int*)42; + var d1 = (in int i) => { Console.WriteLine((1, i)); return p; }; + var d2 = (out int i) => { Console.WriteLine(2); i = 0; return p; }; + var d3 = (ref int i) => { Console.WriteLine((3, i)); return p; }; + var d4 = (int i) => { Console.WriteLine((4, i)); return p; }; + int i = 42; + d1.Invoke(in i); + d2.Invoke(out i); + d3.Invoke(ref i); + d4.Invoke(i); + A.Report(d1); + A.Report(d2); + A.Report(d3); + A.Report(d4); + } +}"; + CompileAndVerify(new[] { sourceA, sourceB, sourceC }, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"(1, 42) +(2, 42) +3 +(4, 0) +<>f__AnonymousDelegate0 +<>f__AnonymousDelegate1 +<>f__AnonymousDelegate2 +<>f__AnonymousDelegate3 +(1, 42) +2 +(3, 0) +(4, 0) +<>f__AnonymousDelegate3 +<>f__AnonymousDelegate2 +<>f__AnonymousDelegate1 +<>f__AnonymousDelegate0 +"); + } + + [WorkItem(55217, "https://github.com/dotnet/roslyn/issues/55217")] + [Fact] + public void SynthesizedDelegateTypes_29() + { + var sourceA = +@"using System; +class A +{ + static void Main() + { + B.M(); + C.M(); + } + internal static void Report(Delegate d) => Console.WriteLine(d.GetType()); +}"; + var sourceB = +@"class B +{ + internal unsafe static void M() + { + A.Report((int* x, int y) => { }); + A.Report((short* x, int y) => { }); + A.Report((int* x, object y) => { }); + } +}"; + var sourceC = +@"class C +{ + internal unsafe static void M() + { + A.Report((int* x, string y) => { }); + A.Report((short* x, int y) => { }); + A.Report((char* x, char y) => { }); + A.Report((int* x, int y) => { }); + A.Report((int* x, object y) => { }); + } +}"; + CompileAndVerify(new[] { sourceA, sourceB, sourceC }, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"<>f__AnonymousDelegate0 +<>f__AnonymousDelegate1 +<>f__AnonymousDelegate2 +<>f__AnonymousDelegate3 +<>f__AnonymousDelegate1 +<>f__AnonymousDelegate4 +<>f__AnonymousDelegate0 +<>f__AnonymousDelegate2 +"); + } + + [Fact] + public void SynthesizedDelegateTypes_30() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Delegate d = F(); + Console.WriteLine(d.GetType()); + } + unsafe static Delegate F() + { + return Local(); + static Delegate Local() where U : unmanaged + { + var d = (T t, U* u) => { Console.WriteLine((t, (int)u)); }; + d.Invoke(default, (U*)42); + return d; + } + } +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"(, 42) +<>f__AnonymousDelegate0`2[System.String,System.Int32] +"); + } + + [Fact] + public void SynthesizedDelegateTypes_31() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(C.F()); + Report(C.F()); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +unsafe class C +{ + internal static Func F = () => + { + return Local1(); + static Delegate Local1() where U : unmanaged + { + return Local2(); + static Delegate Local2() where V : struct + { + var d = U* (T t) => { Console.WriteLine((typeof(T), typeof(U))); return (U*)42; }; + d.Invoke(default); + return d; + } + } + }; +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@" (System.String, System.Int32) +<>f__AnonymousDelegate0`2[System.String,System.Int32] +(System.Single, System.Int32) +<>f__AnonymousDelegate0`2[System.Single,System.Int32] +"); + } + + [Fact] + public void SynthesizedDelegateTypes_32() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(S.F); + Report(S.P); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +unsafe struct S where T : unmanaged +{ + internal static Delegate F = T* () => (T*)1; + internal static Delegate P => S* () => (S*)2; +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"<>f__AnonymousDelegate0`1[System.Int32] +<>f__AnonymousDelegate1`1[System.Char] +"); + } + + [Fact] + public void SynthesizedDelegateTypes_33() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(A.F1()); + Report(A.F1()); + Report(A.B.F2()); + Report(A.B.F2()); + Report(S.C.F3()); + Report(S.C.F3()); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +class A +{ + internal unsafe static Delegate F1() + { + var d = int (int* x, T[] y, S z) => { Console.WriteLine(((int)x, typeof(T), typeof(U))); return 0; }; + d.Invoke((int*)1, null, default); + return d; + } + internal struct B + { + internal unsafe static Delegate F2() + { + var d = int (int* x, T[] y, S z) => { Console.WriteLine(((int)x, typeof(T), typeof(U))); return 0; }; + d.Invoke((int*)2, null, default); + return d; + } + } +} +struct S +{ + internal class C + { + internal unsafe static Delegate F3() + { + var d = int (int* x, T[] y, S z) => { Console.WriteLine(((int)x, typeof(T), typeof(U))); return 0; }; + d.Invoke((int*)3, null, default); + return d; + } + } +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"(1, System.Int32, System.String) +<>f__AnonymousDelegate0`2[System.Int32,System.String] +(1, System.String, System.Int32) +<>f__AnonymousDelegate0`2[System.String,System.Int32] +(2, System.Int32, System.String) +<>f__AnonymousDelegate0`2[System.Int32,System.String] +(2, System.String, System.Int32) +<>f__AnonymousDelegate0`2[System.String,System.Int32] +(3, System.String, System.Int32) +<>f__AnonymousDelegate1`2[System.Int32,System.String] +(3, System.Int32, System.String) +<>f__AnonymousDelegate1`2[System.String,System.Int32] +"); + } + + [Fact] + public void SynthesizedDelegateTypes_34() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(A.B.M1()); + Report(A.M2()); + Report(A.M3()); + Report(A.M4()); + Report(A.B.M1()); + Report(A.M2()); + Report(A.M3()); + Report(A.M4()); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +struct A +{ + internal class B + { + internal unsafe static Delegate M1() + { + var d = void (int* x) => { Console.WriteLine(((int)x, typeof(T), typeof(U), typeof(V))); }; + d.Invoke((int*)1); + return d; + } + } + internal unsafe static Delegate M2() + { + var d = void (int* x) => { Console.WriteLine(((int)x, typeof(T))); }; + d.Invoke((int*)2); + return d; + } + internal unsafe static Delegate M3() + { + var d = void (int* x) => { Console.WriteLine(((int)x, typeof(T), typeof(U))); }; + d.Invoke((int*)3); + return d; + } + internal unsafe static Delegate M4() + { + var d = void (int* x) => { Console.WriteLine(((int)x, typeof(T), typeof(U), typeof(V))); }; + d.Invoke((int*)4); + return d; + } +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"(1, System.Int32, System.String, System.Object) +<>f__AnonymousDelegate0 +(2, System.Int32) +<>f__AnonymousDelegate0 +(3, System.Int32, System.String) +<>f__AnonymousDelegate0 +(4, System.Int32, System.String, System.Object) +<>f__AnonymousDelegate0 +(1, System.String, System.Object, System.Int32) +<>f__AnonymousDelegate0 +(2, System.String) +<>f__AnonymousDelegate0 +(3, System.String, System.Object) +<>f__AnonymousDelegate0 +(4, System.String, System.Object, System.Int32) +<>f__AnonymousDelegate0 +"); + } + + [Fact] + public void SynthesizedDelegateTypes_35() + { + var sourceA = +@".class public A`1 +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } + .method public static void F1(int32* modopt(class A`1) i) { ret } + .method public static int32* F2(!T modopt(class A`1) t) { ldnull throw } +}"; + var refA = CompileIL(sourceA); + + var sourceB = +@"using System; +class B1 : A +{ + unsafe public static Delegate F() + { + return F1; + } +} +class B2 : A +{ + unsafe public static Delegate F() + { + return F2; + } +} +class Program +{ + unsafe static void Main() + { + var d1 = B1.F(); + Report(d1); + var d2 = B2.F(); + Report(d2); + } + static void Report(Delegate d) + { + var t = d.GetType(); + Console.WriteLine(t); + } +}"; + CompileAndVerify(sourceB, references: new[] { refA }, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"<>f__AnonymousDelegate0`1[System.Double] +<>f__AnonymousDelegate1`1[System.Double] +"); + } + + [Fact] + public void SynthesizedDelegateTypes_36() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(S.F1()); + Report(S.F2()); + Report(S.F3()); + Report(S.F4()); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +struct S +{ + internal unsafe static Delegate F1() + { + var d1 = (ref int x) => (ref int y) => { Console.WriteLine((y, typeof(T), typeof(U))); return default(T); }; + int x = 1; + int y = 2; + d1.Invoke(ref x).Invoke(ref y); + return d1; + } + internal unsafe static Delegate F2() + { + var d1 = (ref int x) => (int* y) => { Console.WriteLine(((int)y, typeof(T), typeof(U))); return default(T); }; + int x = 3; + int* y = (int*)4; + d1.Invoke(ref x).Invoke(y); + return d1; + } + internal unsafe static Delegate F3() + { + var d1 = (int* x) => (ref int y) => { Console.WriteLine(((int)x, y, typeof(T), typeof(U))); return default(U); }; + int* x = (int*)5; + int y = 6; + d1.Invoke(x).Invoke(ref y); + return d1; + } + internal unsafe static Delegate F4() + { + var d1 = (int* x) => (int* y) => { Console.WriteLine(((int)x, (int)y, typeof(T), typeof(U))); return default(U); }; + int* x = (int*)7; + int* y = (int*)8; + d1.Invoke(x).Invoke(y); + return d1; + } +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"(2, System.Int32, System.String) +<>F{00000001}`2[System.Int32,<>F{00000001}`2[System.Int32,System.Int32]] +(4, System.Int32, System.String) +<>F{00000001}`2[System.Int32,<>f__AnonymousDelegate0`1[System.Int32]] +(5, 6, System.Int32, System.String) +<>f__AnonymousDelegate1`1[System.String] +(7, 8, System.Int32, System.String) +<>f__AnonymousDelegate2`1[System.String] +"); + } + + [Fact] + public void SynthesizedDelegateTypes_37() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(S.F1()); + Report(S.F2()); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +struct S +{ + internal unsafe static Delegate F1() + { + var d = (int* x) => { Console.WriteLine(((int)x, typeof(T), typeof(U))); return new { A = default(T) }; }; + d.Invoke((int*)1); + return d; + } + internal unsafe static Delegate F2() + { + var d = (int* x) => { Console.WriteLine(((int)x, typeof(T), typeof(U))); return new { B = default(U) }; }; + d.Invoke((int*)2); + return d; + } +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"(1, System.Int32, System.String) +<>f__AnonymousDelegate0`1[System.Int32] +(2, System.Int32, System.String) +<>f__AnonymousDelegate1`1[System.String] +"); + } + + [Fact] + public void SynthesizedDelegateTypes_Constraints_01() + { + var source = +@"using System; +class A +{ + internal void F(T? t) where T : struct + { + Console.WriteLine((typeof(T), t.HasValue ? t.Value.ToString() : """")); + } +} +struct S +{ +} +class Program +{ + static void Main() + { + var a = new A(); + Report(M(a, 1)); + Report(M(a, (short)2)); + Report(M(a, new S())); + } + static void Report(Delegate d) + { + Console.WriteLine(d.GetType()); + } + unsafe static Delegate M(T t, U u) + where T : A + where U : struct + { + var d = void (int* p, T t, U? u) => + { + t.F(u); + }; + d.Invoke((int*)0, t, u); + d.Invoke((int*)1, t, default(U?)); + return d; + } +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"(System.Int32, 1) +(System.Int32, ) +<>f__AnonymousDelegate0`2[A,System.Int32] +(System.Int16, 2) +(System.Int16, ) +<>f__AnonymousDelegate0`2[A,System.Int16] +(S, S) +(S, ) +<>f__AnonymousDelegate0`2[A,S] +"); + } + + [Fact] + public void SynthesizedDelegateTypes_Constraints_02() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(M1(new object(), string.Empty)); + Report(M1(new object(), 1)); + Report(M2(2, new object())); + Report(M2((short)3, (long)4)); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); + unsafe static Delegate M1(T t, U u) + where T : class + where U : T + { + var d = void (int* x, T y, U z) => { Console.WriteLine(((int)x, y.GetType(), z.GetType())); }; + d.Invoke((int*)1, t, u); + return d; + } + unsafe static Delegate M2(T t, U u) + where T : struct + { + var d = void (int* x, T y, U z) => { Console.WriteLine(((int)x, y.GetType(), z.GetType())); }; + d.Invoke((int*)2, t, u); + return d; + } +}"; + CompileAndVerify(source, options: TestOptions.UnsafeReleaseExe, verify: Verification.Skipped, expectedOutput: +@"(1, System.Object, System.String) +<>f__AnonymousDelegate0`2[System.Object,System.String] +(1, System.Object, System.Int32) +<>f__AnonymousDelegate0`2[System.Object,System.Int32] +(2, System.Int32, System.Object) +<>f__AnonymousDelegate0`2[System.Int32,System.Object] +(2, System.Int16, System.Int64) +<>f__AnonymousDelegate0`2[System.Int16,System.Int64] +"); + } + private static void VerifyLocalDelegateType(SemanticModel model, VariableDeclaratorSyntax variable, string expectedInvokeMethod) { var expectedBaseType = ((CSharpCompilation)model.Compilation).GetSpecialType(SpecialType.System_MulticastDelegate); @@ -8914,6 +9674,50 @@ static void Main() CompileAndVerify(source, expectedOutput: @"<>F{00000001}`2[System.Int32,System.Int32]"); } + [WorkItem(56808, "https://github.com/dotnet/roslyn/issues/56808")] + [Fact] + public void Invoke_03() + { + var source = +@"class Program +{ + static void Main() + { + M1(); + M2(); + } + static void M1() + { + var d1 = (ref object obj) => { }; + object obj = null; + var result = d1.BeginInvoke(ref obj, null, null); + d1.EndInvoke(result); + } + unsafe static void M2() + { + var d2 = (int* p) => p; + int* p = (int*)0; + var result = d2.BeginInvoke(p, null, null); + d2.EndInvoke(result); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe); + // https://github.com/dotnet/roslyn/issues/56808: Synthesized delegates should include BeginInvoke() and EndInvoke(). + comp.VerifyDiagnostics( + // (12,25): error CS1061: '' does not contain a definition for 'BeginInvoke' and no accessible extension method 'BeginInvoke' accepting a first argument of type '' could be found (are you missing a using directive or an assembly reference?) + // var result = d1.BeginInvoke(ref obj, null, null); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "BeginInvoke").WithArguments("", "BeginInvoke").WithLocation(12, 25), + // (13,12): error CS1061: '' does not contain a definition for 'EndInvoke' and no accessible extension method 'EndInvoke' accepting a first argument of type '' could be found (are you missing a using directive or an assembly reference?) + // d1.EndInvoke(result); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "EndInvoke").WithArguments("", "EndInvoke").WithLocation(13, 12), + // (19,25): error CS1061: '' does not contain a definition for 'BeginInvoke' and no accessible extension method 'BeginInvoke' accepting a first argument of type '' could be found (are you missing a using directive or an assembly reference?) + // var result = d2.BeginInvoke(p, null, null); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "BeginInvoke").WithArguments("", "BeginInvoke").WithLocation(19, 25), + // (20,12): error CS1061: '' does not contain a definition for 'EndInvoke' and no accessible extension method 'EndInvoke' accepting a first argument of type '' could be found (are you missing a using directive or an assembly reference?) + // d2.EndInvoke(result); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "EndInvoke").WithArguments("", "EndInvoke").WithLocation(20, 12)); + } + [Fact] public void With() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs index 05fb0f4f61bbf..5dccf6ed0710e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs @@ -3603,7 +3603,8 @@ unsafe static void Main() static T Goo(Action x) { throw null; } } "; - var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithAllowUnsafe(true), verify: Verification.Fails).VerifyDiagnostics(); + // PEVerify: [ : Program::Main][mdToken=0x6000001][offset 0x0000002C][found unmanaged pointer][expected unmanaged pointer] Unexpected type on the stack. + var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithAllowUnsafe(true), verify: Verification.FailsPEVerify).VerifyDiagnostics(); var tree = verifier.Compilation.SyntaxTrees.Single(); var model = verifier.Compilation.GetSemanticModel(tree); @@ -3630,7 +3631,8 @@ unsafe static void Main() static T Goo(Action x) { throw null; } } "; - var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithAllowUnsafe(true), verify: Verification.Fails).VerifyDiagnostics(); + // PEVerify: [ : Program::Main][mdToken=0x6000001][offset 0x0000002C][found unmanaged pointer][expected unmanaged pointer] Unexpected type on the stack. + var verifier = CompileAndVerify(source, options: TestOptions.DebugDll.WithAllowUnsafe(true), verify: Verification.FailsPEVerify).VerifyDiagnostics(); var tree = verifier.Compilation.SyntaxTrees.Single(); var model = verifier.Compilation.GetSemanticModel(tree); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs index 467d8668094a5..998107a7da954 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs @@ -3073,7 +3073,7 @@ static void M(string s) }"; var comp = CreateEmptyCompilation(text, new[] { reference1 }); - CompileAndVerify(comp, verify: Verification.Fails). + CompileAndVerify(comp, verify: Verification.FailsPEVerify). VerifyIL("C.M", @" { // Code size 28 (0x1c) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs index 8d653afb5bfbc..994c3203d2d31 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs @@ -469,7 +469,7 @@ struct S {}"); } [Fact] - public void UserDefinedConversion() + public void UserDefinedConversion_01() { var comp = CreateCompilationWithFunctionPointers(@" unsafe class C @@ -513,6 +513,192 @@ .maxstack 1 } } + [Fact, WorkItem(57994, "https://github.com/dotnet/roslyn/issues/57994")] + public void UserDefinedConversion_02() + { + var comp = CreateCompilationWithFunctionPointers(@" +unsafe readonly struct S +{ + public static implicit operator delegate*(S _) => null; + void M() + { + // S -> delegate* -> delegate* + /**/_ = (delegate*)new S()/**/; + } +}"); + + var verifier = CompileAndVerifyFunctionPointers(comp); + verifier.VerifyIL("S.M", @" +{ + // Code size 16 (0x10) + .maxstack 1 + .locals init (S V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj ""S"" + IL_0008: ldloc.0 + IL_0009: call ""delegate* S.op_Implicit(S)"" + IL_000e: pop + IL_000f: ret +} +"); + + VerifyOperationTreeForTest(comp, @" +ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: delegate*) (Syntax: '_ = (delega ... id>)new S()') + Left: + IDiscardOperation (Symbol: delegate* _) (OperationKind.Discard, Type: delegate*) (Syntax: '_') + Right: + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: delegate*, IsImplicit) (Syntax: '(delegate*< ... id>)new S()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: delegate* S.op_Implicit(S _)) (OperationKind.Conversion, Type: delegate*, IsImplicit) (Syntax: '(delegate*< ... id>)new S()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: delegate* S.op_Implicit(S _)) + Operand: + IObjectCreationOperation (Constructor: S..ctor()) (OperationKind.ObjectCreation, Type: S) (Syntax: 'new S()') + Arguments(0) + Initializer: + null +"); + } + + [Fact, WorkItem(57994, "https://github.com/dotnet/roslyn/issues/57994")] + public void UserDefinedConversion_03() + { + var comp = CreateCompilationWithFunctionPointers(@" +unsafe readonly struct S +{ + public static explicit operator delegate*(S _) => null; + void M() + { + // S -> delegate* -> delegate* + /**/_ = (delegate*)new S()/**/; + } +}"); + + var verifier = CompileAndVerifyFunctionPointers(comp); + verifier.VerifyIL("S.M", @" +{ + // Code size 16 (0x10) + .maxstack 1 + .locals init (S V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj ""S"" + IL_0008: ldloc.0 + IL_0009: call ""delegate* S.op_Explicit(S)"" + IL_000e: pop + IL_000f: ret +} +"); + + VerifyOperationTreeForTest(comp, @" +ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: delegate*) (Syntax: '_ = (delega ... id>)new S()') + Left: + IDiscardOperation (Symbol: delegate* _) (OperationKind.Discard, Type: delegate*) (Syntax: '_') + Right: + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: delegate*, IsImplicit) (Syntax: '(delegate*< ... id>)new S()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: delegate* S.op_Explicit(S _)) (OperationKind.Conversion, Type: delegate*, IsImplicit) (Syntax: '(delegate*< ... id>)new S()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: delegate* S.op_Explicit(S _)) + Operand: + IObjectCreationOperation (Constructor: S..ctor()) (OperationKind.ObjectCreation, Type: S) (Syntax: 'new S()') + Arguments(0) + Initializer: + null +"); + } + + [Fact, WorkItem(57994, "https://github.com/dotnet/roslyn/issues/57994")] + public void UserDefinedConversion_04() + { + var comp = CreateCompilationWithFunctionPointers(@" +unsafe readonly struct S +{ + public static implicit operator delegate*(S _) => null; + void M() + { + // S -> delegate* -> delegate* + /**/delegate* _ = new S()/**/; + } +}"); + + var verifier = CompileAndVerifyFunctionPointers(comp); + verifier.VerifyIL("S.M", @" +{ + // Code size 16 (0x10) + .maxstack 1 + .locals init (delegate* V_0, //_ + S V_1) + IL_0000: ldloca.s V_1 + IL_0002: initobj ""S"" + IL_0008: ldloc.1 + IL_0009: call ""delegate* S.op_Implicit(S)"" + IL_000e: stloc.0 + IL_000f: ret +} +"); + + VerifyOperationTreeForTest(comp, @" +IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'delegate* _) (OperationKind.VariableDeclarator, Type: null) (Syntax: '_ = new S()') + Initializer: + IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= new S()') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: delegate*, IsImplicit) (Syntax: 'new S()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: delegate* S.op_Implicit(S _)) (OperationKind.Conversion, Type: delegate*, IsImplicit) (Syntax: 'new S()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: delegate* S.op_Implicit(S _)) + Operand: + IObjectCreationOperation (Constructor: S..ctor()) (OperationKind.ObjectCreation, Type: S) (Syntax: 'new S()') + Arguments(0) + Initializer: + null + Initializer: + null +"); + } + + [Fact, WorkItem(57994, "https://github.com/dotnet/roslyn/issues/57994")] + public void UserDefinedConversion_05() + { + var comp = CreateCompilationWithFunctionPointers(@" +unsafe readonly struct S +{ + public static explicit operator delegate*(S _) => null; + void M() + { + // S -> delegate* -> delegate* + /**/delegate* _ = new S()/**/; + } +}"); + + comp.VerifyDiagnostics( + // (8,45): error CS0266: Cannot implicitly convert type 'S' to 'delegate*'. An explicit conversion exists (are you missing a cast?) + // /**/delegate* _ = new S()/**/; + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "new S()").WithArguments("S", "delegate*").WithLocation(8, 45) + ); + + VerifyOperationTreeForTest(comp, @" +IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'delegate* _) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: '_ = new S()') + Initializer: + IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= new S()') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: delegate*, IsInvalid, IsImplicit) (Syntax: 'new S()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: delegate* S.op_Explicit(S _)) (OperationKind.Conversion, Type: delegate*, IsInvalid, IsImplicit) (Syntax: 'new S()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: delegate* S.op_Explicit(S _)) + Operand: + IObjectCreationOperation (Constructor: S..ctor()) (OperationKind.ObjectCreation, Type: S, IsInvalid) (Syntax: 'new S()') + Arguments(0) + Initializer: + null + Initializer: + null +"); + } + [Fact] public void FunctionPointerToFunctionPointerValid_ReferenceVarianceAndIdentity() { @@ -2646,6 +2832,7 @@ static void Test1(delegate*[] func) {} [Fact, WorkItem(50096, "https://github.com/dotnet/roslyn/issues/50096")] public void FunctionPointerInference_ExactInferenceThroughArray_RefKindMatch() { + // ILVerify: Unexpected type on the stack. ImportCalli not implemented var verifier = CompileAndVerify(@" unsafe { @@ -2659,7 +2846,7 @@ static void Test1(delegate*[] func) { System.Console.Write(t); } } -", expectedOutput: "11", options: TestOptions.UnsafeReleaseExe, verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped); +", expectedOutput: "11", options: TestOptions.UnsafeReleaseExe, verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.FailsILVerify : Verification.Skipped); verifier.VerifyIL("", @" { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ImplicitObjectCreationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ImplicitObjectCreationTests.cs index b328da49afa09..47b4cacbefd34 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ImplicitObjectCreationTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ImplicitObjectCreationTests.cs @@ -2044,6 +2044,41 @@ static void Main() Assert.Equal("System.Object..ctor()", model.GetSymbolInfo(newObject).Symbol?.ToTestDisplayString()); } + [Fact] + public void InRawStringInterpolation() + { + string source = @" +class C +{ + static void Main() + { + System.Console.Write($""""""({new()}) ({new object()})""""""); + } +} +"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "(System.Object) (System.Object)"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var @new = nodes.OfType().Single(); + Assert.Equal("new()", @new.ToString()); + Assert.Equal("System.Object", model.GetTypeInfo(@new).Type.ToTestDisplayString()); + Assert.Equal("System.Object", model.GetTypeInfo(@new).ConvertedType.ToTestDisplayString()); + Assert.Equal("System.Object..ctor()", model.GetSymbolInfo(@new).Symbol?.ToTestDisplayString()); + Assert.False(model.GetConstantValue(@new).HasValue); + + var newObject = nodes.OfType().Single(); + Assert.Equal("new object()", newObject.ToString()); + Assert.Equal("System.Object", model.GetTypeInfo(newObject).Type.ToTestDisplayString()); + Assert.Equal("System.Object", model.GetTypeInfo(newObject).ConvertedType.ToTestDisplayString()); + Assert.Equal("System.Object..ctor()", model.GetSymbolInfo(newObject).Symbol?.ToTestDisplayString()); + } + [Fact] public void InUsing01() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs index 9c3bcbeaf1b2a..650d058df7015 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs @@ -1438,9 +1438,9 @@ public class C options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); comp.VerifyDiagnostics(); - // PE verification fails: [ : C::set_Property] Cannot change initonly field outside its .ctor. + // PEVerify: [ : C::set_Property] Cannot change initonly field outside its .ctor. CompileAndVerify(comp, sourceSymbolValidator: symbolValidator, symbolValidator: symbolValidator, - verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails); + verify: Verification.FailsPEVerify); void symbolValidator(ModuleSymbol m) { @@ -2730,9 +2730,9 @@ public int Property var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); - // [ : C::set_Property] Cannot change initonly field outside its .ctor. + // PEVerify: [ : C::set_Property] Cannot change initonly field outside its .ctor. CompileAndVerify(comp, expectedOutput: "42 43", - verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails); + verify: Verification.FailsPEVerify); } [Fact] @@ -4181,7 +4181,7 @@ public static void Main() targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); // PEVerify: [ : S::set_Property] Cannot change initonly field outside its .ctor. CompileAndVerify(comp1, expectedOutput: "42", - verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails); + verify: Verification.FailsPEVerify); var comp1Ref = new[] { comp1.ToMetadataReference() }; var comp7 = CreateCompilation(source2, references: comp1Ref, @@ -4205,7 +4205,7 @@ public readonly struct S { public int I { get; init; } } -" }, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails, expectedOutput: "1"); +" }, verify: Verification.FailsPEVerify, expectedOutput: "1"); @@ -4243,7 +4243,7 @@ public readonly struct S private readonly int i; public int I { get => i; init => i = value; } } -" }, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails, expectedOutput: "1"); +" }, verify: Verification.FailsPEVerify, expectedOutput: "1"); var s = verifier.Compilation.GetTypeByMetadataName("S"); var i = s.GetMember("I"); @@ -4282,7 +4282,7 @@ public struct S { public readonly int I { get; init; } } -" }, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails, expectedOutput: "1"); +" }, verify: Verification.FailsPEVerify, expectedOutput: "1"); var s = verifier.Compilation.GetTypeByMetadataName("S"); var i = s.GetMember("I"); @@ -4322,7 +4322,7 @@ public struct S private readonly int i; public readonly int I { get => i; init => i = value; } } -" }, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails, expectedOutput: "1"); +" }, verify: Verification.FailsPEVerify, expectedOutput: "1"); var s = verifier.Compilation.GetTypeByMetadataName("S"); var i = s.GetMember("I"); @@ -4417,7 +4417,7 @@ public int I2 } } } -" }, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails, expectedOutput: @"I1 was 1 +" }, verify: Verification.FailsPEVerify, expectedOutput: @"I1 was 1 I1 is 0"); var s = verifier.Compilation.GetTypeByMetadataName("S"); @@ -4551,7 +4551,7 @@ public record Container(Person Person); var comp = CreateCompilation(new[] { IsExternalInitTypeDefinition, source }, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics(); // PEVerify: Cannot change initonly field outside its .ctor. - CompileAndVerify(comp, expectedOutput: "c", verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails); + CompileAndVerify(comp, expectedOutput: "c", verify: Verification.FailsPEVerify); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs index a16e9b0f973a1..e8f04ab535ec6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs @@ -132,9 +132,9 @@ public static void Main(string[] args) // (5,63): error CS1010: Newline in constant // Console.WriteLine($"Jenny don\'t change your number { "); Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(5, 63), - // (6,5): error CS1010: Newline in constant + // (6,5): error CS1039: Unterminated string literal // } - Diagnostic(ErrorCode.ERR_NewlineInConst, "}").WithLocation(6, 5), + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "}").WithLocation(6, 5), // (6,6): error CS1026: ) expected // } Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 6), @@ -159,9 +159,9 @@ public static void Main(string[] args) }"; // too many diagnostics perhaps, but it starts the right way. CreateCompilationWithMscorlib45(source).VerifyDiagnostics( - // (6,5): error CS1010: Newline in constant + // (6,5): error CS1039: Unterminated string literal // } - Diagnostic(ErrorCode.ERR_NewlineInConst, "}").WithLocation(6, 5), + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "}").WithLocation(6, 5), // (6,6): error CS1026: ) expected // } Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 6), @@ -362,9 +362,9 @@ static void Main(string[] args) // (6,31): error CS1010: Newline in constant // Console.WriteLine( $"{" ); Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(6, 31), - // (7,5): error CS1010: Newline in constant + // (7,5): error CS1039: Unterminated string literal // } - Diagnostic(ErrorCode.ERR_NewlineInConst, "}").WithLocation(7, 5), + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "}").WithLocation(7, 5), // (7,6): error CS1026: ) expected // } Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 6), @@ -387,9 +387,9 @@ static void Main(string[] args) var x = $"";"; // The precise error messages are not important, but this must be an error. CreateCompilationWithMscorlib45(source).VerifyDiagnostics( - // (5,19): error CS1010: Newline in constant + // (5,19): error CS1039: Unterminated string literal // var x = $"; - Diagnostic(ErrorCode.ERR_NewlineInConst, ";").WithLocation(5, 19), + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, ";").WithLocation(5, 19), // (5,20): error CS1002: ; expected // var x = $"; Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(5, 20), @@ -398,8 +398,7 @@ static void Main(string[] args) Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 20), // (5,20): error CS1513: } expected // var x = $"; - Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 20) - ); + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 20)); } [Fact] @@ -3818,7 +3817,8 @@ class C var comp = CreateCompilation(new[] { source, interpolatedStringBuilder }, targetFramework: TargetFramework.NetCoreApp); - var verifier = CompileAndVerify(comp, expectedOutput: @" + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + var verifier = CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: @" value:S converted value:C"); @@ -3978,6 +3978,141 @@ public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) ); } + [Fact, WorkItem(58346, "https://github.com/dotnet/roslyn/issues/58346")] + public void UserDefinedConversion_AsFromTypeOfConversion_01() + { + var code = @" +struct S +{ + public static implicit operator S(CustomHandler c) => default; + + static void M() + { + /**/S s = $"""";/**/ + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, handler }); + comp.VerifyDiagnostics( + // (8,25): error CS0029: Cannot implicitly convert type 'string' to 'S' + // /**/S s = $"";/**/ + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""""").WithArguments("string", "S").WithLocation(8, 25) + ); + + VerifyOperationTreeForTest(comp, @" +IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid) (Syntax: 'S s = $"""";') + IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'S s = $""""') + Declarators: + IVariableDeclaratorOperation (Symbol: S s) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 's = $""""') + Initializer: + IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= $""""') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S, IsInvalid, IsImplicit) (Syntax: '$""""') + Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, Constant: """", IsInvalid) (Syntax: '$""""') + Parts(0) + Initializer: + null +"); + } + + [Fact, WorkItem(58346, "https://github.com/dotnet/roslyn/issues/58346")] + public void UserDefinedConversion_AsFromTypeOfConversion_02() + { + var code = @" +struct S +{ + public static implicit operator S(CustomHandler c) => default; + + static void M() + { + /**/S s = (S)$"""";/**/ + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, handler }); + comp.VerifyDiagnostics( + // (8,25): error CS0030: Cannot convert type 'string' to 'S' + // /**/S s = (S)$"";/**/ + Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(S)$""""").WithArguments("string", "S").WithLocation(8, 25) + ); + + VerifyOperationTreeForTest(comp, @" +IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid) (Syntax: 'S s = (S)$"""";') + IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'S s = (S)$""""') + Declarators: + IVariableDeclaratorOperation (Symbol: S s) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 's = (S)$""""') + Initializer: + IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= (S)$""""') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S, IsInvalid) (Syntax: '(S)$""""') + Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, Constant: """", IsInvalid) (Syntax: '$""""') + Parts(0) + Initializer: + null +"); + } + + [Fact, WorkItem(58346, "https://github.com/dotnet/roslyn/issues/58346")] + public void UserDefinedConversion_AsFromTypeOfConversion_03() + { + var code = @" +/**/S s = (CustomHandler)$"""";/**/ + +struct S +{ + public static implicit operator S(CustomHandler c) + { + System.Console.WriteLine(""In handler""); + return default; + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, handler }); + CompileAndVerify(comp, expectedOutput: "In handler").VerifyDiagnostics(); + + VerifyOperationTreeForTest(comp, @" +IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'S s = (Cust ... andler)$"""";') + IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'S s = (CustomHandler)$""""') + Declarators: + IVariableDeclaratorOperation (Symbol: S s) (OperationKind.VariableDeclarator, Type: null) (Syntax: 's = (CustomHandler)$""""') + Initializer: + IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= (CustomHandler)$""""') + IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S S.op_Implicit(CustomHandler c)) (OperationKind.Conversion, Type: S, IsImplicit) (Syntax: '(CustomHandler)$""""') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: S S.op_Implicit(CustomHandler c)) + Operand: + IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: CustomHandler) (Syntax: '(CustomHandler)$""""') + Creation: + IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$""""') + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""""') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""""') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""""') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""""') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Initializer: + null + Content: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, Constant: """") (Syntax: '$""""') + Parts(0) + Initializer: + null +"); + } + [Theory] [InlineData(@"$""Text{1}""")] [InlineData(@"$""Text"" + $""{1}""")] @@ -9205,8 +9340,8 @@ public CustomHandler(int literalLength, int formattedCount, ref C c" + extraCons var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); - comp.VerifyDiagnostics(extraConstructorArg != "" - ? new[] { + comp.VerifyDiagnostics(extraConstructorArg != "" ? + new[] { // (6,1): error CS1620: Argument 3 must be passed with the 'ref' keyword // GetC(ref c).M($"literal" + $""); Diagnostic(ErrorCode.ERR_BadArgRef, "GetC(ref c)").WithArguments("3", "ref").WithLocation(6, 1), @@ -9286,12 +9421,13 @@ public CustomHandler(int literalLength, int formattedCount," + refness + @" C c) var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. var verifier = CompileAndVerify( new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, expectedOutput: "1literal:literal", symbolValidator: validator, sourceSymbolValidator: validator, - verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped); + verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.FailsILVerify : Verification.Skipped); verifier.VerifyIL("", refness == "in" ? @" { // Code size 46 (0x2e) @@ -9515,6 +9651,868 @@ .locals init (S V_0, //s2 IL_0037: ret } "); + + comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: @" +s1.I:1 +s2.I:2"); + } + + [Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")] + public void StructReceiver_Rvalue_ObjectCreationReceiver_01() + { + var code = @" +using System; +using System.Runtime.CompilerServices; +using System.Text; + +var i = 0; +new StructLogger(true, 1).Log($""log:{i++}""); +Console.WriteLine($""(1) i={i}""); + +internal readonly struct StructLogger +{ + private readonly bool _disabled; + private readonly int _id; + + public bool Disabled => _disabled; + public int Id => _id; + + public StructLogger(bool disabled, int id) + { + _disabled = disabled; + _id = id; + } + + public void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler) => Console.WriteLine($""StructLogger#{_id}: "" + handler.GetContent()); +} + +[InterpolatedStringHandler] +internal ref struct DummyHandler +{ + private readonly StringBuilder _builder; + public DummyHandler(int literalLength, int formattedCount, StructLogger structLogger, out bool enabled) + { + Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}""); + enabled = !structLogger.Disabled; + _builder = structLogger.Disabled ? null : new StringBuilder(); + } + public string GetContent() => _builder?.ToString(); + + public void AppendLiteral(string s) => _builder?.Append(s); + public void AppendFormatted(T t) => _builder?.Append(t); +} +"; + + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: @" +Creating DummyHandler from StructLogger#1 +StructLogger#1: +(1) i=0"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 79 (0x4f) + .maxstack 4 + .locals init (int V_0, //i + StructLogger V_1, + DummyHandler V_2, + bool V_3) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.1 + IL_0005: ldc.i4.1 + IL_0006: call ""StructLogger..ctor(bool, int)"" + IL_000b: ldc.i4.4 + IL_000c: ldc.i4.1 + IL_000d: ldloc.1 + IL_000e: ldloca.s V_3 + IL_0010: newobj ""DummyHandler..ctor(int, int, StructLogger, out bool)"" + IL_0015: stloc.2 + IL_0016: ldloc.3 + IL_0017: brfalse.s IL_0031 + IL_0019: ldloca.s V_2 + IL_001b: ldstr ""log:"" + IL_0020: call ""void DummyHandler.AppendLiteral(string)"" + IL_0025: ldloca.s V_2 + IL_0027: ldloc.0 + IL_0028: dup + IL_0029: ldc.i4.1 + IL_002a: add + IL_002b: stloc.0 + IL_002c: call ""void DummyHandler.AppendFormatted(int)"" + IL_0031: ldloca.s V_1 + IL_0033: ldloc.2 + IL_0034: call ""void StructLogger.Log(DummyHandler)"" + IL_0039: ldstr ""(1) i={0}"" + IL_003e: ldloc.0 + IL_003f: box ""int"" + IL_0044: call ""string string.Format(string, object)"" + IL_0049: call ""void System.Console.WriteLine(string)"" + IL_004e: ret +} +"); + } + + [Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")] + public void StructReceiver_Rvalue_ObjectCreationReceiver_02() + { + var code = @" +using System; +using System.Runtime.CompilerServices; +using System.Text; + +var i = 0; +new StructLogger(true, 1).Log($""log:{i++}""); +Console.WriteLine($""(1) i={i}""); +var s = new StructLogger(true, 2); +s.Log($""log:{i++}""); +Console.WriteLine($""(2) i={i}""); + +internal readonly struct StructLogger +{ + private readonly bool _disabled; + private readonly int _id; + + public bool Disabled => _disabled; + public int Id => _id; + + public StructLogger(bool disabled, int id) + { + _disabled = disabled; + _id = id; + } + + public void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler) => Console.WriteLine($""StructLogger#{_id}: "" + handler.GetContent()); +} + +[InterpolatedStringHandler] +internal ref struct DummyHandler +{ + private readonly StringBuilder _builder; + public DummyHandler(int literalLength, int formattedCount, StructLogger structLogger, out bool enabled) + { + Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}""); + enabled = !structLogger.Disabled; + _builder = structLogger.Disabled ? null : new StringBuilder(); + } + public string GetContent() => _builder?.ToString(); + + public void AppendLiteral(string s) => _builder?.Append(s); + public void AppendFormatted(T t) => _builder?.Append(t); +} +"; + + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.DebugExe); + var verifier = CompileAndVerify(comp, expectedOutput: @" +Creating DummyHandler from StructLogger#1 +StructLogger#1: +(1) i=0 +Creating DummyHandler from StructLogger#2 +StructLogger#2: +(2) i=0 +"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 169 (0xa9) + .maxstack 4 + .locals init (int V_0, //i + StructLogger V_1, //s + StructLogger V_2, + DummyHandler V_3, + bool V_4, + StructLogger V_5) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_2 + IL_0004: ldc.i4.1 + IL_0005: ldc.i4.1 + IL_0006: call ""StructLogger..ctor(bool, int)"" + IL_000b: ldc.i4.4 + IL_000c: ldc.i4.1 + IL_000d: ldloc.2 + IL_000e: ldloca.s V_4 + IL_0010: newobj ""DummyHandler..ctor(int, int, StructLogger, out bool)"" + IL_0015: stloc.3 + IL_0016: ldloc.s V_4 + IL_0018: brfalse.s IL_0034 + IL_001a: ldloca.s V_3 + IL_001c: ldstr ""log:"" + IL_0021: call ""void DummyHandler.AppendLiteral(string)"" + IL_0026: nop + IL_0027: ldloca.s V_3 + IL_0029: ldloc.0 + IL_002a: dup + IL_002b: ldc.i4.1 + IL_002c: add + IL_002d: stloc.0 + IL_002e: call ""void DummyHandler.AppendFormatted(int)"" + IL_0033: nop + IL_0034: ldloca.s V_2 + IL_0036: ldloc.3 + IL_0037: call ""void StructLogger.Log(DummyHandler)"" + IL_003c: nop + IL_003d: ldstr ""(1) i={0}"" + IL_0042: ldloc.0 + IL_0043: box ""int"" + IL_0048: call ""string string.Format(string, object)"" + IL_004d: call ""void System.Console.WriteLine(string)"" + IL_0052: nop + IL_0053: ldloca.s V_1 + IL_0055: ldc.i4.1 + IL_0056: ldc.i4.2 + IL_0057: call ""StructLogger..ctor(bool, int)"" + IL_005c: ldloc.1 + IL_005d: stloc.s V_5 + IL_005f: ldc.i4.4 + IL_0060: ldc.i4.1 + IL_0061: ldloc.s V_5 + IL_0063: ldloca.s V_4 + IL_0065: newobj ""DummyHandler..ctor(int, int, StructLogger, out bool)"" + IL_006a: stloc.3 + IL_006b: ldloc.s V_4 + IL_006d: brfalse.s IL_0089 + IL_006f: ldloca.s V_3 + IL_0071: ldstr ""log:"" + IL_0076: call ""void DummyHandler.AppendLiteral(string)"" + IL_007b: nop + IL_007c: ldloca.s V_3 + IL_007e: ldloc.0 + IL_007f: dup + IL_0080: ldc.i4.1 + IL_0081: add + IL_0082: stloc.0 + IL_0083: call ""void DummyHandler.AppendFormatted(int)"" + IL_0088: nop + IL_0089: ldloca.s V_5 + IL_008b: ldloc.3 + IL_008c: call ""void StructLogger.Log(DummyHandler)"" + IL_0091: nop + IL_0092: ldstr ""(2) i={0}"" + IL_0097: ldloc.0 + IL_0098: box ""int"" + IL_009d: call ""string string.Format(string, object)"" + IL_00a2: call ""void System.Console.WriteLine(string)"" + IL_00a7: nop + IL_00a8: ret +} +"); + } + + [Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")] + public void StructArgument_Rvalue_ObjectCreationArgument_01() + { + var code = @" +using System; +using System.Runtime.CompilerServices; +using System.Text; + +var i = 0; +Log(new StructLogger(true, 1), $""log:{i++}""); +Console.WriteLine($""(1) i={i}""); + +static void Log(StructLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""StructLogger#{logger._id}: "" + handler.GetContent()); + +internal readonly struct StructLogger +{ + private readonly bool _disabled; + public readonly int _id; + + public bool Disabled => _disabled; + public int Id => _id; + + public StructLogger(bool disabled, int id) + { + _disabled = disabled; + _id = id; + } +} + +[InterpolatedStringHandler] +internal ref struct DummyHandler +{ + private readonly StringBuilder _builder; + public DummyHandler(int literalLength, int formattedCount, StructLogger structLogger, out bool enabled) + { + Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}""); + enabled = !structLogger.Disabled; + _builder = structLogger.Disabled ? null : new StringBuilder(); + } + public string GetContent() => _builder?.ToString(); + + public void AppendLiteral(string s) => _builder?.Append(s); + public void AppendFormatted(T t) => _builder?.Append(t); +} +"; + + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: @" +Creating DummyHandler from StructLogger#1 +StructLogger#1: +(1) i=0"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 78 (0x4e) + .maxstack 5 + .locals init (int V_0, //i + StructLogger V_1, + DummyHandler V_2, + bool V_3) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.1 + IL_0005: ldc.i4.1 + IL_0006: call ""StructLogger..ctor(bool, int)"" + IL_000b: ldloc.1 + IL_000c: ldc.i4.4 + IL_000d: ldc.i4.1 + IL_000e: ldloc.1 + IL_000f: ldloca.s V_3 + IL_0011: newobj ""DummyHandler..ctor(int, int, StructLogger, out bool)"" + IL_0016: stloc.2 + IL_0017: ldloc.3 + IL_0018: brfalse.s IL_0032 + IL_001a: ldloca.s V_2 + IL_001c: ldstr ""log:"" + IL_0021: call ""void DummyHandler.AppendLiteral(string)"" + IL_0026: ldloca.s V_2 + IL_0028: ldloc.0 + IL_0029: dup + IL_002a: ldc.i4.1 + IL_002b: add + IL_002c: stloc.0 + IL_002d: call ""void DummyHandler.AppendFormatted(int)"" + IL_0032: ldloc.2 + IL_0033: call ""void Program.<
$>g__Log|0_0(StructLogger, DummyHandler)"" + IL_0038: ldstr ""(1) i={0}"" + IL_003d: ldloc.0 + IL_003e: box ""int"" + IL_0043: call ""string string.Format(string, object)"" + IL_0048: call ""void System.Console.WriteLine(string)"" + IL_004d: ret +} +"); + } + + [Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")] + public void StructArgument_Rvalue_ObjectCreationArgument_02() + { + var code = @" +using System; +using System.Runtime.CompilerServices; +using System.Text; + +var i = 0; +Log(new StructLogger(true, 1), $""log:{i++}""); +Console.WriteLine($""(1) i={i}""); + +static void Log(in StructLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""StructLogger#{logger._id}: "" + handler.GetContent()); + +internal readonly struct StructLogger +{ + private readonly bool _disabled; + public readonly int _id; + + public bool Disabled => _disabled; + public int Id => _id; + + public StructLogger(bool disabled, int id) + { + _disabled = disabled; + _id = id; + } +} + +[InterpolatedStringHandler] +internal ref struct DummyHandler +{ + private readonly StringBuilder _builder; + public DummyHandler(int literalLength, int formattedCount, in StructLogger structLogger, out bool enabled) + { + Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}""); + enabled = !structLogger.Disabled; + _builder = structLogger.Disabled ? null : new StringBuilder(); + } + public string GetContent() => _builder?.ToString(); + + public void AppendLiteral(string s) => _builder?.Append(s); + public void AppendFormatted(T t) => _builder?.Append(t); +} +"; + + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: @" +Creating DummyHandler from StructLogger#1 +StructLogger#1: +(1) i=0"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 80 (0x50) + .maxstack 4 + .locals init (int V_0, //i + StructLogger V_1, + DummyHandler V_2, + bool V_3) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.1 + IL_0005: ldc.i4.1 + IL_0006: call ""StructLogger..ctor(bool, int)"" + IL_000b: ldc.i4.4 + IL_000c: ldc.i4.1 + IL_000d: ldloca.s V_1 + IL_000f: ldloca.s V_3 + IL_0011: newobj ""DummyHandler..ctor(int, int, in StructLogger, out bool)"" + IL_0016: stloc.2 + IL_0017: ldloc.3 + IL_0018: brfalse.s IL_0032 + IL_001a: ldloca.s V_2 + IL_001c: ldstr ""log:"" + IL_0021: call ""void DummyHandler.AppendLiteral(string)"" + IL_0026: ldloca.s V_2 + IL_0028: ldloc.0 + IL_0029: dup + IL_002a: ldc.i4.1 + IL_002b: add + IL_002c: stloc.0 + IL_002d: call ""void DummyHandler.AppendFormatted(int)"" + IL_0032: ldloca.s V_1 + IL_0034: ldloc.2 + IL_0035: call ""void Program.<
$>g__Log|0_0(in StructLogger, DummyHandler)"" + IL_003a: ldstr ""(1) i={0}"" + IL_003f: ldloc.0 + IL_0040: box ""int"" + IL_0045: call ""string string.Format(string, object)"" + IL_004a: call ""void System.Console.WriteLine(string)"" + IL_004f: ret +}"); + } + + [Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")] + public void StructArgument_Rvalue_ObjectCreationArgument_03() + { + var code = @" +using System; +using System.Runtime.CompilerServices; +using System.Text; + +var i = 0; +Log(ref new StructLogger(true, 1), $""log:{i++}""); +Console.WriteLine($""(1) i={i}""); + +static void Log(ref StructLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""StructLogger#{logger._id}: "" + handler.GetContent()); + +internal readonly struct StructLogger +{ + private readonly bool _disabled; + public readonly int _id; + + public bool Disabled => _disabled; + public int Id => _id; + + public StructLogger(bool disabled, int id) + { + _disabled = disabled; + _id = id; + } +} + +[InterpolatedStringHandler] +internal ref struct DummyHandler +{ + private readonly StringBuilder _builder; + public DummyHandler(int literalLength, int formattedCount, ref StructLogger structLogger, out bool enabled) + { + Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}""); + enabled = !structLogger.Disabled; + _builder = structLogger.Disabled ? null : new StringBuilder(); + } + public string GetContent() => _builder?.ToString(); + + public void AppendLiteral(string s) => _builder?.Append(s); + public void AppendFormatted(T t) => _builder?.Append(t); +} +"; + + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics( + // (7,9): error CS1510: A ref or out value must be an assignable variable + // Log(ref new StructLogger(true, 1), $"log:{i++}"); + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new StructLogger(true, 1)").WithLocation(7, 9) + ); + } + + [Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")] + public void ReferenceReceiver_Rvalue_ObjectCreationReceiver_01() + { + var code = @" +using System; +using System.Runtime.CompilerServices; +using System.Text; + +var i = 0; +new ClassLogger(true, 1).Log($""log:{i++}""); +Console.WriteLine($""(1) i={i}""); + +internal readonly struct ClassLogger +{ + private readonly bool _disabled; + private readonly int _id; + + public bool Disabled => _disabled; + public int Id => _id; + + public ClassLogger(bool disabled, int id) + { + _disabled = disabled; + _id = id; + } + + public void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler) => Console.WriteLine($""ClassLogger#{_id}: "" + handler.GetContent()); +} + +[InterpolatedStringHandler] +internal ref struct DummyHandler +{ + private readonly StringBuilder _builder; + public DummyHandler(int literalLength, int formattedCount, ClassLogger ClassLogger, out bool enabled) + { + Console.WriteLine($""Creating DummyHandler from ClassLogger#{ClassLogger.Id}""); + enabled = !ClassLogger.Disabled; + _builder = ClassLogger.Disabled ? null : new StringBuilder(); + } + public string GetContent() => _builder?.ToString(); + + public void AppendLiteral(string s) => _builder?.Append(s); + public void AppendFormatted(T t) => _builder?.Append(t); +} +"; + + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: @" +Creating DummyHandler from ClassLogger#1 +ClassLogger#1: +(1) i=0"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 79 (0x4f) + .maxstack 4 + .locals init (int V_0, //i + ClassLogger V_1, + DummyHandler V_2, + bool V_3) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.1 + IL_0005: ldc.i4.1 + IL_0006: call ""ClassLogger..ctor(bool, int)"" + IL_000b: ldc.i4.4 + IL_000c: ldc.i4.1 + IL_000d: ldloc.1 + IL_000e: ldloca.s V_3 + IL_0010: newobj ""DummyHandler..ctor(int, int, ClassLogger, out bool)"" + IL_0015: stloc.2 + IL_0016: ldloc.3 + IL_0017: brfalse.s IL_0031 + IL_0019: ldloca.s V_2 + IL_001b: ldstr ""log:"" + IL_0020: call ""void DummyHandler.AppendLiteral(string)"" + IL_0025: ldloca.s V_2 + IL_0027: ldloc.0 + IL_0028: dup + IL_0029: ldc.i4.1 + IL_002a: add + IL_002b: stloc.0 + IL_002c: call ""void DummyHandler.AppendFormatted(int)"" + IL_0031: ldloca.s V_1 + IL_0033: ldloc.2 + IL_0034: call ""void ClassLogger.Log(DummyHandler)"" + IL_0039: ldstr ""(1) i={0}"" + IL_003e: ldloc.0 + IL_003f: box ""int"" + IL_0044: call ""string string.Format(string, object)"" + IL_0049: call ""void System.Console.WriteLine(string)"" + IL_004e: ret +} +"); + } + + [Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")] + public void ReferenceArgument_Rvalue_ObjectCreationArgument_01() + { + var code = @" +using System; +using System.Runtime.CompilerServices; +using System.Text; + +var i = 0; +Log(new ClassLogger(true, 1), $""log:{i++}""); +Console.WriteLine($""(1) i={i}""); + +static void Log(ClassLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""ClassLogger#{logger._id}: "" + handler.GetContent()); + +internal readonly struct ClassLogger +{ + private readonly bool _disabled; + public readonly int _id; + + public bool Disabled => _disabled; + public int Id => _id; + + public ClassLogger(bool disabled, int id) + { + _disabled = disabled; + _id = id; + } +} + +[InterpolatedStringHandler] +internal ref struct DummyHandler +{ + private readonly StringBuilder _builder; + public DummyHandler(int literalLength, int formattedCount, ClassLogger ClassLogger, out bool enabled) + { + Console.WriteLine($""Creating DummyHandler from ClassLogger#{ClassLogger.Id}""); + enabled = !ClassLogger.Disabled; + _builder = ClassLogger.Disabled ? null : new StringBuilder(); + } + public string GetContent() => _builder?.ToString(); + + public void AppendLiteral(string s) => _builder?.Append(s); + public void AppendFormatted(T t) => _builder?.Append(t); +} +"; + + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: @" +Creating DummyHandler from ClassLogger#1 +ClassLogger#1: +(1) i=0"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 78 (0x4e) + .maxstack 5 + .locals init (int V_0, //i + ClassLogger V_1, + DummyHandler V_2, + bool V_3) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.1 + IL_0005: ldc.i4.1 + IL_0006: call ""ClassLogger..ctor(bool, int)"" + IL_000b: ldloc.1 + IL_000c: ldc.i4.4 + IL_000d: ldc.i4.1 + IL_000e: ldloc.1 + IL_000f: ldloca.s V_3 + IL_0011: newobj ""DummyHandler..ctor(int, int, ClassLogger, out bool)"" + IL_0016: stloc.2 + IL_0017: ldloc.3 + IL_0018: brfalse.s IL_0032 + IL_001a: ldloca.s V_2 + IL_001c: ldstr ""log:"" + IL_0021: call ""void DummyHandler.AppendLiteral(string)"" + IL_0026: ldloca.s V_2 + IL_0028: ldloc.0 + IL_0029: dup + IL_002a: ldc.i4.1 + IL_002b: add + IL_002c: stloc.0 + IL_002d: call ""void DummyHandler.AppendFormatted(int)"" + IL_0032: ldloc.2 + IL_0033: call ""void Program.<
$>g__Log|0_0(ClassLogger, DummyHandler)"" + IL_0038: ldstr ""(1) i={0}"" + IL_003d: ldloc.0 + IL_003e: box ""int"" + IL_0043: call ""string string.Format(string, object)"" + IL_0048: call ""void System.Console.WriteLine(string)"" + IL_004d: ret +} +"); + } + + [Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")] + public void ReferenceArgument_Rvalue_ObjectCreationArgument_02() + { + var code = @" +using System; +using System.Runtime.CompilerServices; +using System.Text; + +var i = 0; +Log(new ClassLogger(true, 1), $""log:{i++}""); +Console.WriteLine($""(1) i={i}""); + +static void Log(in ClassLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""ClassLogger#{logger._id}: "" + handler.GetContent()); + +internal readonly struct ClassLogger +{ + private readonly bool _disabled; + public readonly int _id; + + public bool Disabled => _disabled; + public int Id => _id; + + public ClassLogger(bool disabled, int id) + { + _disabled = disabled; + _id = id; + } +} + +[InterpolatedStringHandler] +internal ref struct DummyHandler +{ + private readonly StringBuilder _builder; + public DummyHandler(int literalLength, int formattedCount, in ClassLogger ClassLogger, out bool enabled) + { + Console.WriteLine($""Creating DummyHandler from ClassLogger#{ClassLogger.Id}""); + enabled = !ClassLogger.Disabled; + _builder = ClassLogger.Disabled ? null : new StringBuilder(); + } + public string GetContent() => _builder?.ToString(); + + public void AppendLiteral(string s) => _builder?.Append(s); + public void AppendFormatted(T t) => _builder?.Append(t); +} +"; + + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: @" +Creating DummyHandler from ClassLogger#1 +ClassLogger#1: +(1) i=0"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 80 (0x50) + .maxstack 4 + .locals init (int V_0, //i + ClassLogger V_1, + DummyHandler V_2, + bool V_3) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.1 + IL_0005: ldc.i4.1 + IL_0006: call ""ClassLogger..ctor(bool, int)"" + IL_000b: ldc.i4.4 + IL_000c: ldc.i4.1 + IL_000d: ldloca.s V_1 + IL_000f: ldloca.s V_3 + IL_0011: newobj ""DummyHandler..ctor(int, int, in ClassLogger, out bool)"" + IL_0016: stloc.2 + IL_0017: ldloc.3 + IL_0018: brfalse.s IL_0032 + IL_001a: ldloca.s V_2 + IL_001c: ldstr ""log:"" + IL_0021: call ""void DummyHandler.AppendLiteral(string)"" + IL_0026: ldloca.s V_2 + IL_0028: ldloc.0 + IL_0029: dup + IL_002a: ldc.i4.1 + IL_002b: add + IL_002c: stloc.0 + IL_002d: call ""void DummyHandler.AppendFormatted(int)"" + IL_0032: ldloca.s V_1 + IL_0034: ldloc.2 + IL_0035: call ""void Program.<
$>g__Log|0_0(in ClassLogger, DummyHandler)"" + IL_003a: ldstr ""(1) i={0}"" + IL_003f: ldloc.0 + IL_0040: box ""int"" + IL_0045: call ""string string.Format(string, object)"" + IL_004a: call ""void System.Console.WriteLine(string)"" + IL_004f: ret +}"); + } + + [Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")] + public void ReferenceArgument_Rvalue_ObjectCreationArgument_03() + { + var code = @" +using System; +using System.Runtime.CompilerServices; +using System.Text; + +var i = 0; +Log(ref new ClassLogger(true, 1), $""log:{i++}""); +Console.WriteLine($""(1) i={i}""); + +static void Log(ref ClassLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""ClassLogger#{logger._id}: "" + handler.GetContent()); + +internal readonly struct ClassLogger +{ + private readonly bool _disabled; + public readonly int _id; + + public bool Disabled => _disabled; + public int Id => _id; + + public ClassLogger(bool disabled, int id) + { + _disabled = disabled; + _id = id; + } +} + +[InterpolatedStringHandler] +internal ref struct DummyHandler +{ + private readonly StringBuilder _builder; + public DummyHandler(int literalLength, int formattedCount, ref ClassLogger ClassLogger, out bool enabled) + { + Console.WriteLine($""Creating DummyHandler from ClassLogger#{ClassLogger.Id}""); + enabled = !ClassLogger.Disabled; + _builder = ClassLogger.Disabled ? null : new StringBuilder(); + } + public string GetContent() => _builder?.ToString(); + + public void AppendLiteral(string s) => _builder?.Append(s); + public void AppendFormatted(T t) => _builder?.Append(t); +} +"; + + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics( + // (7,9): error CS1510: A ref or out value must be an assignable variable + // Log(ref new ClassLogger(true, 1), $"log:{i++}"); + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new ClassLogger(true, 1)").WithLocation(7, 9) + ); } [Theory] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 3d22d654f2b61..17855adb842ae 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -5250,21 +5250,12 @@ static void Main() // (7,13): error CS1599: The return type of a method, delegate, or function pointer cannot be 'TypedReference' // d = TypedReference () => throw null; Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "TypedReference").WithArguments("System.TypedReference").WithLocation(7, 13), - // (7,13): error CS8917: The delegate type could not be inferred. - // d = TypedReference () => throw null; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "TypedReference () => throw null").WithLocation(7, 13), // (8,13): error CS1599: The return type of a method, delegate, or function pointer cannot be 'RuntimeArgumentHandle' // d = RuntimeArgumentHandle () => throw null; Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "RuntimeArgumentHandle").WithArguments("System.RuntimeArgumentHandle").WithLocation(8, 13), - // (8,13): error CS8917: The delegate type could not be inferred. - // d = RuntimeArgumentHandle () => throw null; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "RuntimeArgumentHandle () => throw null").WithLocation(8, 13), // (9,13): error CS1599: The return type of a method, delegate, or function pointer cannot be 'ArgIterator' // d = ArgIterator () => throw null; - Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "ArgIterator").WithArguments("System.ArgIterator").WithLocation(9, 13), - // (9,13): error CS8917: The delegate type could not be inferred. - // d = ArgIterator () => throw null; - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "ArgIterator () => throw null").WithLocation(9, 13)); + Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "ArgIterator").WithArguments("System.ArgIterator").WithLocation(9, 13)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NamedAndOptionalTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NamedAndOptionalTests.cs index a6fca5b9c53db..df1b5a1787dc3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NamedAndOptionalTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NamedAndOptionalTests.cs @@ -772,7 +772,7 @@ static void Main() // default(IntPtr) as "load zero, convert to type", rather than making a stack slot and calling // init on it. - var c = CompileAndVerify(source, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails); + var c = CompileAndVerify(source, options: TestOptions.UnsafeReleaseDll, verify: Verification.FailsPEVerify); c.VerifyIL("C.Main", @"{ // Code size 13 (0xd) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs index 11099313ee706..781d1b889736d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs @@ -399,16 +399,6 @@ public void M() var tree = Parse(source, options: TestOptions.RegularPreview); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); - - var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); - SimpleLambdaExpressionSyntax node = comp.GlobalNamespace.GetTypeMember("C") - .GetMember("M") - .GetNonNullSyntaxNode() - .DescendantNodes() - .OfType() - .Single(); - var methodSymbol = (IMethodSymbol)model.GetSymbolInfo(node).Symbol!; - Assert.True(methodSymbol.Parameters[0].IsNullChecked); } [Fact] @@ -426,17 +416,6 @@ public void M() var tree = Parse(source, options: TestOptions.RegularPreview); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); - - var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); - ParenthesizedLambdaExpressionSyntax node = comp.GlobalNamespace.GetTypeMember("C") - .GetMember("M") - .GetNonNullSyntaxNode() - .DescendantNodes() - .OfType() - .Single(); - var methodSymbol = (IMethodSymbol)model.GetSymbolInfo(node).Symbol!; - Assert.True(methodSymbol.Parameters[0].IsNullChecked); - Assert.False(methodSymbol.Parameters[1].IsNullChecked); } [Fact] @@ -454,16 +433,6 @@ public void M() var tree = Parse(source, options: TestOptions.RegularPreview); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); - - CSharpSemanticModel model = (CSharpSemanticModel)comp.GetSemanticModel(tree); - Syntax.ParenthesizedLambdaExpressionSyntax node = comp.GlobalNamespace.GetTypeMember("C") - .GetMember("M") - .GetNonNullSyntaxNode() - .DescendantNodes() - .OfType() - .Single(); - var methodSymbol = (IMethodSymbol)model.GetSymbolInfo(node).Symbol!; - Assert.True(methodSymbol.Parameters[0].IsNullChecked); } [Fact] @@ -571,16 +540,6 @@ public void M() var tree = Parse(source, options: TestOptions.RegularPreview); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); - - CSharpSemanticModel model = (CSharpSemanticModel)comp.GetSemanticModel(tree); - ParenthesizedLambdaExpressionSyntax node = comp.GlobalNamespace.GetTypeMember("C") - .GetMember("M") - .GetNonNullSyntaxNode() - .DescendantNodes() - .OfType() - .Single(); - var methodSymbol = (IMethodSymbol)model.GetSymbolInfo(node).Symbol!; - Assert.True(methodSymbol.Parameters[0].IsNullChecked); } [Fact] @@ -598,17 +557,6 @@ public void M() var tree = Parse(source, options: TestOptions.RegularPreview); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); - - CSharpSemanticModel model = (CSharpSemanticModel)comp.GetSemanticModel(tree); - ParenthesizedLambdaExpressionSyntax node = comp.GlobalNamespace.GetTypeMember("C") - .GetMember("M") - .GetNonNullSyntaxNode() - .DescendantNodes() - .OfType() - .Single(); - var methodSymbol = (IMethodSymbol)model.GetSymbolInfo(node).Symbol!; - Assert.True(methodSymbol.Parameters[0].IsNullChecked); - Assert.False(methodSymbol.Parameters[1].IsNullChecked); } [Fact] @@ -626,21 +574,10 @@ public void M() var tree = Parse(source, options: TestOptions.RegularPreview); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); - - CSharpSemanticModel model = (CSharpSemanticModel)comp.GetSemanticModel(tree); - ParenthesizedLambdaExpressionSyntax node = comp.GlobalNamespace.GetTypeMember("C") - .GetMember("M") - .GetNonNullSyntaxNode() - .DescendantNodes() - .OfType() - .Single(); - var methodSymbol = (IMethodSymbol)model.GetSymbolInfo(node).Symbol!; - Assert.True(methodSymbol.Parameters[0].IsNullChecked); - Assert.True(methodSymbol.Parameters[1].IsNullChecked); } [Fact] - public void NullCheckedDiscard() + public void NullCheckedDiscard_1() { var source = @" using System; @@ -649,21 +586,40 @@ class C public void M() { Func func1 = (_!!) => 42; + Func func2 = (_!!, x) => 42; } }"; var tree = Parse(source, options: TestOptions.RegularPreview); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); + } - CSharpSemanticModel model = (CSharpSemanticModel)comp.GetSemanticModel(tree); - ParenthesizedLambdaExpressionSyntax node = comp.GlobalNamespace.GetTypeMember("C") - .GetMember("M") - .GetNonNullSyntaxNode() - .DescendantNodes() - .OfType() - .Single(); - var methodSymbol = (IMethodSymbol)model.GetSymbolInfo(node).Symbol!; - Assert.True(methodSymbol.Parameters[0].IsNullChecked); + [Fact] + public void NullCheckedDiscard_2() + { + var source = @" +using System; +class C +{ + public Action action0 = (_, _) => { }; // 1 + public Action action1 = (_!!, _) => { }; // 1 + public Action action2 = (_, _!!) => { }; // 2 + public Action action3 = (_!!, _!!) => { }; // 3, 4 +}"; + var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + compilation.VerifyDiagnostics( + // (6,46): error CS8990: Discard parameter cannot be null-checked. + // public Action action1 = (_!!, _) => { }; // 1 + Diagnostic(ErrorCode.ERR_DiscardCannotBeNullChecked, "_").WithLocation(6, 46), + // (7,49): error CS8990: Discard parameter cannot be null-checked. + // public Action action2 = (_, _!!) => { }; // 2 + Diagnostic(ErrorCode.ERR_DiscardCannotBeNullChecked, "_").WithLocation(7, 49), + // (8,46): error CS8990: Discard parameter cannot be null-checked. + // public Action action3 = (_!!, _!!) => { }; // 3, 4 + Diagnostic(ErrorCode.ERR_DiscardCannotBeNullChecked, "_").WithLocation(8, 46), + // (8,51): error CS8990: Discard parameter cannot be null-checked. + // public Action action3 = (_!!, _!!) => { }; // 3, 4 + Diagnostic(ErrorCode.ERR_DiscardCannotBeNullChecked, "_").WithLocation(8, 51)); } [Fact] @@ -680,9 +636,9 @@ public void M(out string x!!) }"; var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics( - // (5,31): error CS8720: By-reference parameter 'x' cannot be null-checked. + // (5,31): error CS8994: 'out' parameter 'x' cannot be null-checked. // public void M(out string x!!) - Diagnostic(ErrorCode.ERR_NullCheckingOnByRefParameter, "!!").WithArguments("x").WithLocation(5, 31)); + Diagnostic(ErrorCode.ERR_NullCheckingOnOutParameter, "!!").WithArguments("x").WithLocation(5, 31)); } [Fact] @@ -698,10 +654,7 @@ public void M(ref string x!!) } }"; var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyDiagnostics( - // (5,31): error CS8720: By-reference parameter 'x' cannot be null-checked. - // public void M(ref string x!!) - Diagnostic(ErrorCode.ERR_NullCheckingOnByRefParameter, "!!").WithArguments("x").WithLocation(5, 31)); + compilation.VerifyDiagnostics(); } [Fact] @@ -714,10 +667,7 @@ public static void Main() { } public void M(in string x!!) { } }"; var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); - compilation.VerifyDiagnostics( - // (5,30): error CS8720: By-reference parameter 'x' cannot be null-checked. - // public void M(in string x!!) { } - Diagnostic(ErrorCode.ERR_NullCheckingOnByRefParameter, "!!").WithArguments("x").WithLocation(5, 30)); + compilation.VerifyDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index eb347595b103e..6456143bb87a9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -10390,12 +10390,10 @@ void M() compilation.VerifyDiagnostics(); } - [Fact] + [Fact, WorkItem(37309, "https://github.com/dotnet/roslyn/issues/37309")] public void NonNullTypesTrue_Foreach() { var source = @" - - class C { #nullable enable @@ -10459,22 +10457,34 @@ public void M2() compilation.VerifyTypes(); compilation.VerifyDiagnostics( - // (60,11): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context. + // (58,11): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // string?[] FalseNCollection() => throw null!; // 5 - Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(60, 11), - // (16,13): warning CS8602: Dereference of a possibly null reference. + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(58, 11), + // (14,13): warning CS8602: Dereference of a possibly null reference. // ns /*T:string?*/ .ToString(); // 1 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns").WithLocation(16, 13), - // (26,13): warning CS8602: Dereference of a possibly null reference. + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns").WithLocation(14, 13), + // (24,13): warning CS8602: Dereference of a possibly null reference. // ns1 /*T:string?*/ .ToString(); // 2 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns1").WithLocation(26, 13), - // (36,13): warning CS8602: Dereference of a possibly null reference. + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns1").WithLocation(24, 13), + // (34,13): warning CS8602: Dereference of a possibly null reference. // ns /*T:string?*/ .ToString(); // 3 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns").WithLocation(36, 13), - // (46,13): warning CS8602: Dereference of a possibly null reference. + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns").WithLocation(34, 13), + // (44,13): warning CS8602: Dereference of a possibly null reference. // ns1 /*T:string?*/ .ToString(); // 4 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns1").WithLocation(46, 13) + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns1").WithLocation(44, 13) ); + + var tree = compilation.SyntaxTrees.Single(); + var model = compilation.GetSemanticModel(tree); + var foreachSyntax = tree.GetRoot().DescendantNodes().OfType().ToArray(); + + var type1 = foreachSyntax[0].Type; + Assert.Equal("string", type1.ToString()); + Assert.Equal("System.String!", model.GetTypeInfo(type1).Type.ToTestDisplayString(includeNonNullable: true)); + + var type2 = foreachSyntax[1].Type; + Assert.Equal("string?", type2.ToString()); + Assert.Equal("System.String?", model.GetTypeInfo(type2).Type.ToTestDisplayString(includeNonNullable: true)); } [WorkItem(30840, "https://github.com/dotnet/roslyn/issues/30840")] @@ -20417,6 +20427,346 @@ public C() ); } + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] + public void NotNullWhenTrue_UserDefinedOperator_Implicit() + { + CSharpCompilation c = CreateCompilation(new[] { @" +using System.Diagnostics.CodeAnalysis; +class C +{ + void M(C? c) + { + if (c) + { + c.ToString(); // ok + } + else + { + c.ToString(); // 1 + } + } + + void M2(C? c) + { + bool b = c; + if (b) + { + c.ToString(); // 2 (not tracked through assignment) + } + } + + public static implicit operator bool([NotNullWhen(true)] C? c) { return true; } +} +", NotNullWhenAttributeDefinition }, options: WithNullableEnable()); + + c.VerifyDiagnostics( + // (13,7): warning CS8602: Possible dereference of a null reference. + // c.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c").WithLocation(13, 7), + // (22,7): warning CS8602: Possible dereference of a null reference. + // c.ToString(); // 2 (not tracked through assignment) + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c").WithLocation(22, 7) + ); + + VerifyAnnotationsAndMetadata(c, "C.op_Implicit", NotNullWhenTrue); + } + + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] + public void NotNullWhenTrue_UserDefinedOperator_Explicit() + { + CSharpCompilation c = CreateCompilation(new[] { @" +using System.Diagnostics.CodeAnalysis; +class C +{ + void M(C? c) + { + if ((bool)c) + { + c.ToString(); // ok + } + else + { + c.ToString(); // 1 + } + } + + void M2(C? c) + { + bool b = (bool)c; + if (b) + { + c.ToString(); // 2 (not tracked through assignment) + } + } + + public static explicit operator bool([NotNullWhen(true)] C? c) { return true; } +} +", NotNullWhenAttributeDefinition }, options: WithNullableEnable()); + + c.VerifyDiagnostics( + // (13,7): warning CS8602: Possible dereference of a null reference. + // c.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c").WithLocation(13, 7), + // (22,7): warning CS8602: Possible dereference of a null reference. + // c.ToString(); // 2 (not tracked through assignment) + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c").WithLocation(22, 7) + ); + + VerifyAnnotationsAndMetadata(c, "C.op_Explicit", NotNullWhenTrue); + } + + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] + public void NotNullWhenTrue_UserDefinedOperator_Derived() + { + CSharpCompilation c = CreateCompilation(new[] { @" +using System.Diagnostics.CodeAnalysis; +class C : B +{ + void M(C? c) + { + if (c) + { + c.ToString(); // ok + } + else + { + c.ToString(); // 1 + } + } +} + +public class B +{ + public static implicit operator bool([NotNullWhen(true)] B? b) { return true; } +} +", NotNullWhenAttributeDefinition }, options: WithNullableEnable()); + + c.VerifyDiagnostics( + // (13,7): warning CS8602: Possible dereference of a null reference. + // c.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c").WithLocation(13, 7) + ); + + VerifyAnnotationsAndMetadata(c, "B.op_Implicit", NotNullWhenTrue); + } + + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] + public void NotNull_UserDefinedOperator1() + { + CSharpCompilation c = CreateCompilation(new[] { @" +#pragma warning disable CS0660, CS0661 // no equals, hashcode +using System.Diagnostics.CodeAnalysis; +public class C +{ + public void Main(C? c, C? c2) + { + if(c == c2) + { + c.ToString(); + c2.ToString(); // 1 + } + else + { + c.ToString(); + c2.ToString(); // 2 + } + } + + public static bool operator ==([NotNull] C? c1, C? c2) + { + throw null!; + } + + public static bool operator !=(C? c1, C? c2) + { + return true; + } +} +", NotNullAttributeDefinition }, options: WithNullableEnable()); + + c.VerifyDiagnostics( + // (11,13): warning CS8602: Dereference of a possibly null reference. + // c2.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c2").WithLocation(11, 13), + // (16,13): warning CS8602: Dereference of a possibly null reference. + // c2.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c2").WithLocation(16, 13) + ); + + VerifyAnnotationsAndMetadata(c, "C.op_Equality", NotNull, None); + } + + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] + public void NotNull_UserDefinedOperator2() + { + CSharpCompilation c = CreateCompilation(new[] { @" +#pragma warning disable CS0660, CS0661 // no equals, hashcode +using System.Diagnostics.CodeAnalysis; +public class C +{ + public void Main(C? c, C? c2) + { + if(c == c2) + { + c.ToString(); // 1 + c2.ToString(); + } + else + { + c.ToString(); // 2 + c2.ToString(); + } + } + + public static bool operator ==(C? c1, [NotNull]C? c2) + { + throw null!; + } + + public static bool operator !=(C? c1, C? c2) + { + return true; + } +} +", NotNullAttributeDefinition }, options: WithNullableEnable()); + + c.VerifyDiagnostics( + // (10,11): warning CS8602: Dereference of a possibly null reference. + // c.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c").WithLocation(10, 11), + // (15,13): warning CS8602: Dereference of a possibly null reference. + // c.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c").WithLocation(15, 13) + ); + + VerifyAnnotationsAndMetadata(c, "C.op_Equality", None, NotNull); + } + + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] + public void NotNullWhen_UserDefinedConversion_Completeness() + { + CSharpCompilation c = CreateCompilation(new[] { @" +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +public class C +{ + public bool Field; + + public static bool M0(bool b = new C()) // 1 + { + _ = new C() { Field = new C() }; + _ = new bool[] { new C(), true }; + _ = new [] { new C(), true }; + + return new C(); + return true; // 2 + } + + public static IEnumerable Iterator() + { + yield return new C(); + yield return true; + } + + public static implicit operator bool([NotNullWhen(true)] C? c) => c != null; +} +", NotNullWhenAttributeDefinition }, options: WithNullableEnable()); + + c.VerifyDiagnostics( + // (9,36): error CS1736: Default parameter value for 'b' must be a compile-time constant + // public static bool M0(bool b = new C()) // 1 + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new C()").WithArguments("b").WithLocation(9, 36), + // (16,9): warning CS0162: Unreachable code detected + // return true; // 2 + Diagnostic(ErrorCode.WRN_UnreachableCode, "return").WithLocation(16, 9) + ); + } + + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] + public void DisallowNull_UserDefinedOperator_01() + { + CSharpCompilation c = CreateCompilation(new[] { @" +#pragma warning disable CS0660, CS0661 // no equals, hashcode +using System.Diagnostics.CodeAnalysis; + +public class C +{ + public static void M0(C? c) + { + bool b = c; // 1 + b = new C(); + } + + public static void M0(C? c1, C? c2) + { + bool b = c1 == c2; // 2 + b = c2 != c1; // 3 + b = new C() == new C(); + } + + public static implicit operator bool([DisallowNull] C? c) => c != null; + + public static bool operator ==([DisallowNull] C? c1, C? c2) => (object?)c1 == c2; + public static bool operator !=([DisallowNull] C? c1, C? c2) => (object?)c1 != c2; +} +", DisallowNullAttributeDefinition }, options: WithNullableEnable()); + + c.VerifyDiagnostics( + // (9,18): warning CS8604: Possible null reference argument for parameter 'c' in 'C.implicit operator bool(C? c)'. + // bool b = c; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "c").WithArguments("c", "C.implicit operator bool(C? c)").WithLocation(9, 18), + // (15,18): warning CS8604: Possible null reference argument for parameter 'c1' in 'bool C.operator ==(C? c1, C? c2)'. + // bool b = c1 == c2; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "c1").WithArguments("c1", "bool C.operator ==(C? c1, C? c2)").WithLocation(15, 18), + // (16,13): warning CS8604: Possible null reference argument for parameter 'c1' in 'bool C.operator !=(C? c1, C? c2)'. + // b = c2 != c1; // 3 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "c2").WithArguments("c1", "bool C.operator !=(C? c1, C? c2)").WithLocation(16, 13) + ); + } + + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] + public void DisallowNull_UserDefinedOperator_02() + { + CSharpCompilation c = CreateCompilation(new[] { @" +#pragma warning disable CS0660, CS0661 // no equals, hashcode +using System.Diagnostics.CodeAnalysis; + +public struct S +{ + public static void M0(S? s) + { + bool? b = s; // 1 + b = new S(); + } + + public static void M0(S? s1, S? s2) + { + bool b = s1 == s2; // 2 + b = s2 != s1; // 3 + b = new S() == new S(); + } + + public static implicit operator bool([DisallowNull] S? s) => s != null; + + public static bool operator ==([DisallowNull] S? s1, S? s2) => throw null!; + public static bool operator !=([DisallowNull] S? s1, S? s2) => throw null!; +} +", DisallowNullAttributeDefinition }, options: WithNullableEnable()); + + c.VerifyDiagnostics( + // (9,19): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] + // bool? b = s; // 1 + Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "s").WithLocation(9, 19), + // (15,18): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] + // bool b = s1 == s2; // 2 + Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "s1").WithLocation(15, 18), + // (16,13): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] + // b = s2 != s1; // 3 + Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "s2").WithLocation(16, 13) + ); + } + [Fact, WorkItem(58598, "https://github.com/dotnet/roslyn/issues/58598")] public void MemberNotNull_NullConstant() { @@ -39279,6 +39629,7 @@ public class C [WorkItem(48605, "https://github.com/dotnet/roslyn/issues/48605")] [WorkItem(48134, "https://github.com/dotnet/roslyn/issues/48134")] [WorkItem(49136, "https://github.com/dotnet/roslyn/issues/49136")] + [WorkItem(49575, "https://github.com/dotnet/roslyn/issues/49575")] public void AllowNullNotNullInputParam_UpdatesArgumentState() { var source = @" @@ -39301,7 +39652,7 @@ public static void M2(string? s) public static void M3(string? s) { C c = s; - s.ToString(); // 1 + s.ToString(); } public static void MExt([AllowNull, NotNull] this string s) { throw null!; } @@ -39312,13 +39663,8 @@ public class C } } "; - // we should respect postconditions on a conversion parameter - // https://github.com/dotnet/roslyn/issues/49575 var comp = CreateNullableCompilation(new[] { source, AllowNullAttributeDefinition, NotNullAttributeDefinition }); - comp.VerifyDiagnostics( - // (21,9): warning CS8602: Dereference of a possibly null reference. - // s.ToString(); // 1 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(21, 9)); + comp.VerifyDiagnostics(); } [Fact] @@ -64236,8 +64582,32 @@ void Test2(string x2, string? y2) } " }, options: WithNullableEnable()); - c.VerifyDiagnostics( - ); + c.VerifyDiagnostics(); + } + + [Fact] + public void RawStringInterpolation_01() + { + CSharpCompilation c = CreateCompilation(new[] { @" +class C +{ + static void Main() + { + } + + void Test1(string x1, string? y1) + { + x1 = $""""""{y1}""""""; + } + + void Test2(string x2, string? y2) + { + x2 = $""""""{y2}"""""" ?? x2; + } +} +" }, options: WithNullableEnable()); + + c.VerifyDiagnostics(); } [Theory] @@ -68199,7 +68569,7 @@ class CL2 ); } - [Fact] + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] public void BinaryOperator_03_WithDisallowAndAllowNull() { CSharpCompilation c = CreateNullableCompilation(new[] { @" @@ -68243,23 +68613,13 @@ void Test4(string x4, CL1 y4, CL2 z4) } ", AllowNullAttributeDefinition, DisallowNullAttributeDefinition }); - // Analyze operator call properly (honoring [Disallow|Allow|Maybe|NotNull] attribute annotations) https://github.com/dotnet/roslyn/issues/32671 c.VerifyDiagnostics( - // (8,24): warning CS8604: Possible null reference argument for parameter 'y' in 'CL0 CL0.operator +(string? x, CL0 y)'. - // CL0? z1 = x1 + y1; - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y1").WithArguments("y", "CL0 CL0.operator +(string? x, CL0 y)").WithLocation(8, 24), - // (19,18): warning CS8604: Possible null reference argument for parameter 'x' in 'CL1? CL1.operator +(string x, CL1? y)'. - // CL1 z2 = x2 + y2; // 1, 2 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x2").WithArguments("x", "CL1? CL1.operator +(string x, CL1? y)").WithLocation(19, 18), // (19,18): warning CS8600: Converting null literal or possible null value to non-nullable type. // CL1 z2 = x2 + y2; // 1, 2 Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x2 + y2").WithLocation(19, 18), - // (29,23): warning CS8604: Possible null reference argument for parameter 'y' in 'CL0 CL0.operator +(string? x, CL0 y)'. - // CL2 u3 = x3 + y3 + z3; - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y3").WithArguments("y", "CL0 CL0.operator +(string? x, CL0 y)").WithLocation(29, 23), - // (34,18): warning CS8604: Possible null reference argument for parameter 'x' in 'CL2 CL2.operator +(CL1 x, CL2 y)'. - // CL2 u4 = x4 + y4 + z4; - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x4 + y4").WithArguments("x", "CL2 CL2.operator +(CL1 x, CL2 y)").WithLocation(34, 18) + // (19,23): warning CS8604: Possible null reference argument for parameter 'y' in 'CL1? CL1.operator +(string x, CL1? y)'. + // CL1 z2 = x2 + y2; // 1, 2 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y2").WithArguments("y", "CL1? CL1.operator +(string x, CL1? y)").WithLocation(19, 23) ); } @@ -68840,7 +69200,7 @@ static void F(S x, S? y) comp.VerifyDiagnostics(); } - [Fact] + [Fact, WorkItem(32671, "https://github.com/dotnet/roslyn/issues/32671")] public void BinaryOperator_15_WithDisallowNull() { var source = @" @@ -68858,9 +69218,14 @@ static void F(S? x, S? y) s = y + y; // 2 } }"; - // Analyze operator call properly (honoring [Disallow|Allow|Maybe|NotNull] attribute annotations) https://github.com/dotnet/roslyn/issues/32671 var comp = CreateCompilation(new[] { source, DisallowNullAttributeDefinition }, options: WithNullableEnable()); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (11,17): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] + // s = x + y; // 1 + Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "y").WithLocation(11, 17), + // (13,17): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] + // s = y + y; // 2 + Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "y").WithLocation(13, 17)); } [Fact] @@ -87020,7 +87385,7 @@ void M() foreach (var (index, alpha) in Identity(items3)) { index/*T:int?*/.ToString(); - alpha/*T:Alpha!*/.ToString(); // Should warn, be Alpha? + alpha/*T:Alpha?*/.ToString(); // 2 } } @@ -87029,12 +87394,13 @@ void M() "; var comp = CreateCompilation(source, options: WithNullableEnable()); - // https://github.com/dotnet/roslyn/issues/39736, missing the warning on the alpha dereference - // from the deconstruction case comp.VerifyDiagnostics( // (23,13): warning CS8602: Dereference of a possibly null reference. - // alpha.ToString(); // 1 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "alpha").WithLocation(23, 13)); + // alpha/*T:Alpha?*/.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "alpha").WithLocation(23, 13), + // (28,13): warning CS8602: Dereference of a possibly null reference. + // alpha/*T:Alpha?*/.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "alpha").WithLocation(28, 13)); comp.VerifyTypes(); } @@ -87209,6 +87575,40 @@ void M(T parameter) comp.VerifyDiagnostics(); } + [Fact, WorkItem(52042, "https://github.com/dotnet/roslyn/issues/52042")] + public void ForEach_Deconstruction() + { + var src = @" +#nullable enable +using System; +using System.Linq; + +public class C { + public void M() { + foreach(var (a, b) in (new int[]{}).Select(x => M1())) + { + a.ToString(); + b.ToString(); + } + } + + static (String?, String?) M1() + { + return (null, null); + } +}"; + + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (10,13): warning CS8602: Dereference of a possibly null reference. + // a.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a").WithLocation(10, 13), + // (11,13): warning CS8602: Dereference of a possibly null reference. + // b.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b").WithLocation(11, 13) + ); + } + [Theory] [InlineData("System.Collections.IEnumerator?")] [InlineData("System.Collections.Generic.IEnumerator?")] @@ -112290,7 +112690,7 @@ interface I2 compilation2.VerifyEmitDiagnostics(); // Verification against a corlib not named exactly mscorlib is expected to fail. - CompileAndVerify(compilation2, verify: Verification.Fails); + CompileAndVerify(compilation2, verify: Verification.FailsPEVerify); Assert.Equal(TypeKind.Struct, compilation2.GetTypeByMetadataName("A").TypeKind); Assert.Equal(TypeKind.Enum, compilation2.GetTypeByMetadataName("B").TypeKind); @@ -112301,7 +112701,7 @@ interface I2 var compilation3 = CreateEmptyCompilation(source2, options: WithNullableEnable(TestOptions.ReleaseDll), references: new[] { compilation1.ToMetadataReference(), MinCorlibRef }); compilation3.VerifyEmitDiagnostics(); - CompileAndVerify(compilation3, verify: Verification.Fails); + CompileAndVerify(compilation3, verify: Verification.FailsPEVerify); Assert.Equal(TypeKind.Struct, compilation3.GetTypeByMetadataName("A").TypeKind); Assert.Equal(TypeKind.Enum, compilation3.GetTypeByMetadataName("B").TypeKind); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableTests.cs index 8d4341c8f4666..1c82e2586ee3e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableTests.cs @@ -209,7 +209,7 @@ static void Main() } }"; - verifier = CompileAndVerify(source: source3, expectedOutput: "1", verify: Verification.Fails); + verifier = CompileAndVerify(source: source3, expectedOutput: "1", verify: Verification.FailsPEVerify); verifier = CompileAndVerify(source: source3, expectedOutput: "1", parseOptions: TestOptions.Regular.WithPEVerifyCompatFeature()); } @@ -268,7 +268,7 @@ static void F(int line, bool b) "; foreach (string type in new[] { "int", "ushort", "byte", "long", "float", "decimal" }) { - CompileAndVerify(source: source4.Replace("TYPE", type), expectedOutput: "0", verify: Verification.Fails); + CompileAndVerify(source: source4.Replace("TYPE", type), expectedOutput: "0", verify: Verification.FailsPEVerify); CompileAndVerify(source: source4.Replace("TYPE", type), expectedOutput: "0", parseOptions: TestOptions.Regular.WithPEVerifyCompatFeature()); } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs index a65f2332c223d..659ccca0544f9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs @@ -11189,7 +11189,7 @@ void enumerateChildren(IOperation iop) { numChildren++; Assert.NotNull(iop); - foreach (var child in iop.Children) + foreach (var child in iop.ChildOperations) { enumerateChildren(child); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs index 4fc72d7c33b28..43d63721ece68 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs @@ -9037,7 +9037,8 @@ public static void RemoveDetail(this TMain main, TChild child) } }"; var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); - CompileAndVerify(compilation, expectedOutput: + // ILVerify: Unrecognized arguments for delegate .ctor. + CompileAndVerify(compilation, verify: Verification.FailsILVerify, expectedOutput: @"RemoveDetail RemoveDetail RemoveDetail @@ -11292,7 +11293,8 @@ private static bool Contains(this System.Collections.Generic.IEnumerable a throw new NotImplementedException(); }"; - CompileAndVerify(code, expectedOutput: @"2"); + // ILVerify: Unrecognized arguments for delegate .ctor. + CompileAndVerify(code, verify: Verification.FailsILVerify, expectedOutput: @"2"); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTestBase.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTestBase.cs index 1123370d1d3ed..ced278c5f442f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTestBase.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTestBase.cs @@ -441,19 +441,19 @@ protected static void AssertEmpty(SymbolInfo info) Assert.Equal(CandidateReason.None, info.CandidateReason); } - protected static void VerifyDecisionDagDump(Compilation comp, string expectedDecisionDag) + protected static void VerifyDecisionDagDump(Compilation comp, string expectedDecisionDag, int index = 0) where T : CSharpSyntaxNode { #if DEBUG var tree = comp.SyntaxTrees.First(); - var node = tree.GetRoot().DescendantNodes().OfType().First(); + var node = tree.GetRoot().DescendantNodes().OfType().ElementAt(index); var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); var binder = model.GetEnclosingBinder(node.SpanStart); var decisionDag = node switch { - SwitchStatementSyntax n => ((BoundSwitchStatement)binder.BindStatement(n, BindingDiagnosticBag.Discarded)).DecisionDag, - SwitchExpressionSyntax n => ((BoundSwitchExpression)binder.BindExpression(n, BindingDiagnosticBag.Discarded)).DecisionDag, - IsPatternExpressionSyntax n => ((BoundIsPatternExpression)binder.BindExpression(n, BindingDiagnosticBag.Discarded)).DecisionDag, + SwitchStatementSyntax n => ((BoundSwitchStatement)binder.BindStatement(n, BindingDiagnosticBag.Discarded)).ReachabilityDecisionDag, + SwitchExpressionSyntax n => ((BoundSwitchExpression)binder.BindExpression(n, BindingDiagnosticBag.Discarded)).ReachabilityDecisionDag, + IsPatternExpressionSyntax n => ((BoundIsPatternExpression)binder.BindExpression(n, BindingDiagnosticBag.Discarded)).ReachabilityDecisionDag, var v => throw ExceptionUtilities.UnexpectedValue(v) }; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs index 6fe353dc666a5..d2b1da7954173 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs @@ -6221,7 +6221,7 @@ static int CopyRefInt(ref int z) var compilation = CreateCompilation(program, options: TestOptions.DebugExe.WithAllowUnsafe(true)); compilation.VerifyDiagnostics( ); - var comp = CompileAndVerify(compilation, expectedOutput: "ok"); + var comp = CompileAndVerify(compilation, expectedOutput: "ok", verify: Verification.FailsILVerify); } [Fact] @@ -6517,7 +6517,10 @@ unsafe static void Main() False"; var compilation = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe); compilation.VerifyDiagnostics(); - CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: Verification.Fails); + // PEVerify: + // [ : Program::Main][mdToken=0x6000001][offset 0x00000002] Unmanaged pointers are not a verifiable type. + // [ : Program::Main][mdToken= 0x6000001][offset 0x00000002] Unable to resolve token. + CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs index f0a96415b7ae9..287caaaeb5f78 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs @@ -470,7 +470,8 @@ public static RGBColor FromRainbow(Rainbow colorBand) => var compilation = CreateCompilation(source, options: TestOptions.DebugExe); compilation.VerifyDiagnostics( ); - var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput); + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + var comp = CompileAndVerify(compilation, verify: Verification.FailsILVerify, expectedOutput: expectedOutput); } [Fact, WorkItem(35278, "https://github.com/dotnet/roslyn/issues/35278")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs index 03049a27447f5..9f7ad9d147944 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs @@ -3610,7 +3610,7 @@ void M(object obj) [12]: when ((i % 2) == 0) ? [14] : [13] [13]: leaf `default` [14]: leaf `case int i when (i % 2) == 0:` -", boundSwitch.DecisionDag.Dump()); +", boundSwitch.ReachabilityDecisionDag.Dump()); } [Fact, WorkItem(53868, "https://github.com/dotnet/roslyn/issues/53868")] @@ -3696,7 +3696,7 @@ void M(C c) Console.Write(3); break; }` -", boundSwitch.DecisionDag.Dump()); +", boundSwitch.ReachabilityDecisionDag.Dump()); } [Fact, WorkItem(53868, "https://github.com/dotnet/roslyn/issues/53868")] @@ -3777,7 +3777,7 @@ void M(C c) Console.Write(2); break; }` -", boundSwitch.DecisionDag.Dump()); +", boundSwitch.ReachabilityDecisionDag.Dump()); } [Fact, WorkItem(53868, "https://github.com/dotnet/roslyn/issues/53868")] @@ -3823,7 +3823,7 @@ or bool` [9]: leaf `< 5 or string { Length: 1 } or bool` -", boundIsPattern.DecisionDag.Dump()); +", boundIsPattern.ReachabilityDecisionDag.Dump()); } [Fact, WorkItem(53868, "https://github.com/dotnet/roslyn/issues/53868")] @@ -3865,7 +3865,7 @@ void M(object obj) [9]: t0 is bool ? [10] : [11] [10]: leaf `bool => 3` [11]: leaf `_ => 4` -", boundSwitch.DecisionDag.Dump()); +", boundSwitch.ReachabilityDecisionDag.Dump()); } #endif } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs index 3a2f80d06c143..d151cbd684a47 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs @@ -230,6 +230,210 @@ .locals init (char V_0, //first ); } + [Fact] + [WorkItem(57731, "https://github.com/dotnet/roslyn/issues/57731")] + public void ListPattern_Codegen() + { + var source = @" +public class X +{ + static int Test1(int[] x) + { + switch (x) + { + case [.., 1] and [1, ..]: return 0; + } + + return 1; + } + static int Test2(int[] x) + { + switch (x) + { + case [2, ..] and [.., 1]: return 0; + } + + return 3; + } + static int Test3(int[] x) + { + switch (x) + { + case [2, ..]: return 4; + case [.., 1]: return 5; + } + + return 3; + } + static int Test4(int[] x) + { + switch (x) + { + case [2, ..]: return 4; + case [.., 1]: return 5; + case [6, .., 7]: return 8; + } + + return 3; + } +} +"; + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + var verifier = CompileAndVerify(new[] { source, TestSources.Index, TestSources.Range }, parseOptions: TestOptions.RegularWithListPatterns, + options: TestOptions.ReleaseDll, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + AssertEx.Multiple( + () => verifier.VerifyIL("X.Test1", @" +{ + // Code size 29 (0x1d) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: brfalse.s IL_001b + IL_0003: ldarg.0 + IL_0004: ldlen + IL_0005: conv.i4 + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: blt.s IL_001b + IL_000b: ldarg.0 + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: sub + IL_000f: ldelem.i4 + IL_0010: ldc.i4.1 + IL_0011: bne.un.s IL_001b + IL_0013: ldarg.0 + IL_0014: ldc.i4.0 + IL_0015: ldelem.i4 + IL_0016: ldc.i4.1 + IL_0017: bne.un.s IL_001b + IL_0019: ldc.i4.0 + IL_001a: ret + IL_001b: ldc.i4.1 + IL_001c: ret +}"), + () => verifier.VerifyIL("X.Test2", @" +{ + // Code size 29 (0x1d) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: brfalse.s IL_001b + IL_0003: ldarg.0 + IL_0004: ldlen + IL_0005: conv.i4 + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: blt.s IL_001b + IL_000b: ldarg.0 + IL_000c: ldc.i4.0 + IL_000d: ldelem.i4 + IL_000e: ldc.i4.2 + IL_000f: bne.un.s IL_001b + IL_0011: ldarg.0 + IL_0012: ldloc.0 + IL_0013: ldc.i4.1 + IL_0014: sub + IL_0015: ldelem.i4 + IL_0016: ldc.i4.1 + IL_0017: bne.un.s IL_001b + IL_0019: ldc.i4.0 + IL_001a: ret + IL_001b: ldc.i4.3 + IL_001c: ret +}"), + () => verifier.VerifyIL("X.Test3", @" +{ + // Code size 33 (0x21) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: brfalse.s IL_001f + IL_0003: ldarg.0 + IL_0004: ldlen + IL_0005: conv.i4 + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: blt.s IL_001f + IL_000b: ldarg.0 + IL_000c: ldc.i4.0 + IL_000d: ldelem.i4 + IL_000e: ldc.i4.2 + IL_000f: beq.s IL_001b + IL_0011: ldarg.0 + IL_0012: ldloc.0 + IL_0013: ldc.i4.1 + IL_0014: sub + IL_0015: ldelem.i4 + IL_0016: ldc.i4.1 + IL_0017: beq.s IL_001d + IL_0019: br.s IL_001f + IL_001b: ldc.i4.4 + IL_001c: ret + IL_001d: ldc.i4.5 + IL_001e: ret + IL_001f: ldc.i4.3 + IL_0020: ret +}"), + () => verifier.VerifyIL("X.Test4", @" +{ + // Code size 51 (0x33) + .maxstack 3 + .locals init (int V_0, + int V_1, + int V_2) + IL_0000: ldarg.0 + IL_0001: brfalse.s IL_0031 + IL_0003: ldarg.0 + IL_0004: ldlen + IL_0005: conv.i4 + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: blt.s IL_0031 + IL_000b: ldarg.0 + IL_000c: ldc.i4.0 + IL_000d: ldelem.i4 + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: ldc.i4.2 + IL_0011: beq.s IL_002b + IL_0013: ldarg.0 + IL_0014: ldloc.0 + IL_0015: ldc.i4.1 + IL_0016: sub + IL_0017: ldelem.i4 + IL_0018: stloc.2 + IL_0019: ldloc.2 + IL_001a: ldc.i4.1 + IL_001b: beq.s IL_002d + IL_001d: ldloc.0 + IL_001e: ldc.i4.2 + IL_001f: blt.s IL_0031 + IL_0021: ldloc.1 + IL_0022: ldc.i4.6 + IL_0023: bne.un.s IL_0031 + IL_0025: ldloc.2 + IL_0026: ldc.i4.7 + IL_0027: beq.s IL_002f + IL_0029: br.s IL_0031 + IL_002b: ldc.i4.4 + IL_002c: ret + IL_002d: ldc.i4.5 + IL_002e: ret + IL_002f: ldc.i4.8 + IL_0030: ret + IL_0031: ldc.i4.3 + IL_0032: ret +} +") + ); + } + [Fact] public void ListPattern_LangVer() { @@ -1381,6 +1585,33 @@ public void M(int[] a) ); } + [Fact] + public void SlicePattern_NullValue() + { + var source = @" +#nullable enable +class C +{ + public int Length => 3; + public int this[int i] => 0; + public int[]? Slice(int i, int j) => null; + + public static void Main() + { + if (new C() is [.. var s0] && s0 == null) + System.Console.Write(1); + if (new C() is [.. null]) + System.Console.Write(2); + if (new C() is not [.. {}]) + System.Console.Write(3); + } +} +"; + var compilation = CreateCompilationWithIndexAndRange(source, options: TestOptions.ReleaseExe); + compilation.VerifyEmitDiagnostics(); + CompileAndVerify(compilation, expectedOutput: "12"); + } + [Fact] public void ListPattern_MemberLookup_StaticIndexer() { @@ -2362,9 +2593,10 @@ public static void Main() } } "; + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } var compilation = CreateCompilation(new[] { source, TestSources.Index }, options: TestOptions.ReleaseExe); compilation.VerifyEmitDiagnostics(); - CompileAndVerify(compilation, expectedOutput: "123"); + CompileAndVerify(compilation, expectedOutput: "123", verify: Verification.FailsILVerify); } [Fact] @@ -2533,6 +2765,41 @@ public static void Test5(T t) where T : IIndexable, ICountableViaLength, ICou ); } + [Fact, WorkItem(59466, "https://github.com/dotnet/roslyn/issues/59466")] + public void AlwaysTruePattern() + { + var source = @" +_ = new S() is [..var y]; +y.ToString(); + +_ = new S() is [..]; +_ = new S() is [..[..]]; +_ = new S() is not [..]; + +struct S +{ + public int Length => 1; + public int this[int i] => 42; + public S this[System.Range r] => default; +} +"; + var comp = CreateCompilationWithIndexAndRangeAndSpan(source); + comp.VerifyEmitDiagnostics( + // (2,5): warning CS8794: An expression of type 'S' always matches the provided pattern. + // _ = new S() is [..var y]; + Diagnostic(ErrorCode.WRN_IsPatternAlways, "new S() is [..var y]").WithArguments("S").WithLocation(2, 5), + // (5,5): warning CS8794: An expression of type 'S' always matches the provided pattern. + // _ = new S() is [..]; + Diagnostic(ErrorCode.WRN_IsPatternAlways, "new S() is [..]").WithArguments("S").WithLocation(5, 5), + // (6,5): warning CS8794: An expression of type 'S' always matches the provided pattern. + // _ = new S() is [..[..]]; + Diagnostic(ErrorCode.WRN_IsPatternAlways, "new S() is [..[..]]").WithArguments("S").WithLocation(6, 5), + // (7,5): error CS8518: An expression of type 'S' can never match the provided pattern. + // _ = new S() is not [..]; + Diagnostic(ErrorCode.ERR_IsPatternImpossible, "new S() is not [..]").WithArguments("S").WithLocation(7, 5) + ); + } + [Fact] public void ListPattern_ValEscape() { @@ -3504,7 +3771,8 @@ public class C "; var compilation = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); compilation.VerifyDiagnostics(); - CompileAndVerify(compilation, expectedOutput: expectedOutput); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: Verification.FailsILVerify); } [Fact] @@ -3853,14 +4121,14 @@ public void M() rest.ToString(); // 1 if (new C() is [1, ..var rest2]) - rest2.Value.ToString(); // 2 + rest2.Value.ToString(); // (assumed not-null) else - rest2.Value.ToString(); // 3, 4 + rest2.Value.ToString(); // 2, 3 if (new C() is [1, ..var rest3]) - rest3.ToString(); // 5 + rest3.ToString(); // (assumed not-null) else - rest3.ToString(); // 6, 7 + rest3.ToString(); // 4, 5 if (new C() is [1, ..var rest4]) { @@ -3868,11 +4136,11 @@ public void M() rest4 = null; } else - rest4.ToString(); // 8, 9 + rest4.ToString(); // 6, 7 if (new C() is [1, ..var rest5]) { - rest5.ToString(); // 10 + rest5.ToString(); // (assumed not-null) rest5 = default; } } @@ -3883,33 +4151,24 @@ public void M() // (14,13): error CS0165: Use of unassigned local variable 'rest' // rest.ToString(); // 1 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest").WithArguments("rest").WithLocation(14, 13), - // (17,13): warning CS8629: Nullable value type may be null. - // rest2.Value.ToString(); // 2 - Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "rest2").WithLocation(17, 13), // (19,13): warning CS8629: Nullable value type may be null. - // rest2.Value.ToString(); // 3, 4 + // rest2.Value.ToString(); // 2, 3 Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "rest2").WithLocation(19, 13), // (19,13): error CS0165: Use of unassigned local variable 'rest2' - // rest2.Value.ToString(); // 3, 4 + // rest2.Value.ToString(); // 2, 3 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest2").WithArguments("rest2").WithLocation(19, 13), - // (22,13): warning CS8602: Dereference of a possibly null reference. - // rest3.ToString(); // 5 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest3").WithLocation(22, 13), // (24,13): warning CS8602: Dereference of a possibly null reference. - // rest3.ToString(); // 6, 7 + // rest3.ToString(); // 4, 5 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest3").WithLocation(24, 13), // (24,13): error CS0165: Use of unassigned local variable 'rest3' - // rest3.ToString(); // 6, 7 + // rest3.ToString(); // 4, 5 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest3").WithArguments("rest3").WithLocation(24, 13), // (32,13): warning CS8602: Dereference of a possibly null reference. - // rest4.ToString(); // 8, 9 + // rest4.ToString(); // 6, 7 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest4").WithLocation(32, 13), // (32,13): error CS0165: Use of unassigned local variable 'rest4' - // rest4.ToString(); // 8, 9 - Diagnostic(ErrorCode.ERR_UseDefViolation, "rest4").WithArguments("rest4").WithLocation(32, 13), - // (36,13): warning CS8602: Dereference of a possibly null reference. - // rest5.ToString(); // 10 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest5").WithLocation(36, 13) + // rest4.ToString(); // 6, 7 + Diagnostic(ErrorCode.ERR_UseDefViolation, "rest4").WithArguments("rest4").WithLocation(32, 13) ); var tree = compilation.SyntaxTrees.First(); @@ -3931,6 +4190,53 @@ void verify(VarPatternSyntax declaration, string name, string expectedType) } } + [Fact] + public void SlicePattern_Nullability_Annotation() + { + var source = @" +#nullable enable +class C +{ + public int Length => throw null!; + public int this[int i] => throw null!; + public int[]? Slice(int i, int j) => throw null!; + + public void M() + { + if (this is [1, ..var slice]) + slice.ToString(); + if (this is [1, ..[] list]) + list.ToString(); + } +} +"; + var compilation = CreateCompilationWithIndexAndRange(source); + compilation.VerifyEmitDiagnostics(); + + var tree = compilation.SyntaxTrees.Single(); + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + var nodes = tree.GetRoot().DescendantNodes().OfType(); + Assert.Collection(nodes, + d => verify(d, "slice", "int[]?", "int[]"), + d => verify(d, "list", "int[]?", "int[]") + ); + + void verify(SyntaxNode designation, string syntax, string declaredType, string type) + { + Assert.Equal(syntax, designation.ToString()); + var model = compilation.GetSemanticModel(tree); + var symbol = model.GetDeclaredSymbol(designation); + Assert.Equal(SymbolKind.Local, symbol.Kind); + Assert.Equal(declaredType, ((ILocalSymbol)symbol).Type.ToDisplayString()); + var typeInfo = model.GetTypeInfo(designation); + Assert.Null(typeInfo.Type); + Assert.Null(typeInfo.ConvertedType); + typeInfo = model.GetTypeInfo(designation.Parent); + Assert.Equal(type, typeInfo.Type.ToDisplayString()); + Assert.Equal(type, typeInfo.ConvertedType.ToDisplayString()); + } + } + [Fact] public void SlicePattern_Nullability_RangeIndexer() { @@ -3951,14 +4257,14 @@ public void M() rest.ToString(); // 1 if (new C() is [1, ..var rest2]) - rest2.Value.ToString(); // 2 + rest2.Value.ToString(); // (assumed not-null) else - rest2.Value.ToString(); // 3, 4 + rest2.Value.ToString(); // 2, 3 if (new C() is [1, ..var rest3]) - rest3.ToString(); // 5 + rest3.ToString(); // (assumed not-null) else - rest3.ToString(); // 6, 7 + rest3.ToString(); // 4, 5 if (new C() is [1, ..var rest4]) { @@ -3966,7 +4272,7 @@ public void M() rest4 = null; } else - rest4.ToString(); // 8, 9 + rest4.ToString(); // 6, 7 } } "; @@ -3975,29 +4281,23 @@ public void M() // (15,13): error CS0165: Use of unassigned local variable 'rest' // rest.ToString(); // 1 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest").WithArguments("rest").WithLocation(15, 13), - // (18,13): warning CS8629: Nullable value type may be null. - // rest2.Value.ToString(); // 2 - Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "rest2").WithLocation(18, 13), // (20,13): warning CS8629: Nullable value type may be null. - // rest2.Value.ToString(); // 3, 4 + // rest2.Value.ToString(); // 2, 3 Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "rest2").WithLocation(20, 13), // (20,13): error CS0165: Use of unassigned local variable 'rest2' - // rest2.Value.ToString(); // 3, 4 + // rest2.Value.ToString(); // 2, 3 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest2").WithArguments("rest2").WithLocation(20, 13), - // (23,13): warning CS8602: Dereference of a possibly null reference. - // rest3.ToString(); // 5 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest3").WithLocation(23, 13), // (25,13): warning CS8602: Dereference of a possibly null reference. - // rest3.ToString(); // 6, 7 + // rest3.ToString(); // 4, 5 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest3").WithLocation(25, 13), // (25,13): error CS0165: Use of unassigned local variable 'rest3' - // rest3.ToString(); // 6, 7 + // rest3.ToString(); // 4, 5 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest3").WithArguments("rest3").WithLocation(25, 13), // (33,13): warning CS8602: Dereference of a possibly null reference. - // rest4.ToString(); // 8, 9 + // rest4.ToString(); // 6, 7 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest4").WithLocation(33, 13), // (33,13): error CS0165: Use of unassigned local variable 'rest4' - // rest4.ToString(); // 8, 9 + // rest4.ToString(); // 6, 7 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest4").WithArguments("rest4").WithLocation(33, 13) ); } @@ -4696,63 +4996,63 @@ public void M() [not null] => 0, }; - _ = this switch // we didn't test for [.. null] but we're looking for an example with Length=1. // 1 + _ = this switch // didn't test for [.. null] but the slice is assumed not-null { null or { Length: not 1 } => 0, [.. [null]] => 0, [not null] => 0, }; - _ = this switch // didn't test for [.. [not null]] // // 2 + _ = this switch // didn't test for [.. [not null]] // 1 { null or { Length: not 1 } => 0, [.. [null]] => 0, }; - _ = this switch // didn't test for [.. [not null]] // // 3 + _ = this switch // didn't test for [.. [not null]] // 2 { null or { Length: not 1 } => 0, [.. null] => 0, [.. [null]] => 0, }; - _ = this switch // didn't test for [.. null, _] // we're trying to construct an example with Length=1, the slice may not be null // 4 + _ = this switch // didn't test for [.. null, _] // we're trying to construct an example with Length=1, the slice may not be null // 3 { null or { Length: not 1 } => 0, [.. [not null]] => 0, }; - _ = this switch // didn't test for [_, .. null, _, _, _] // we're trying to construct an example with Length=4, the slice may not be null // 5 + _ = this switch // didn't test for [_, .. null, _, _, _] // we're trying to construct an example with Length=4, the slice may not be null // 4 { null or { Length: not 4 } => 0, [_, .. [_, not null], _] => 0, }; - _ = this switch // we should consider this switch exhaustive // 6 + _ = this switch // exhaustive { null or { Length: not 4 } => 0, [_, .. [_, _], _] => 0, }; - _ = this switch // didn't test for [_, .. [_, null], _] // 7 + _ = this switch // didn't test for [_, .. [_, null], _] // 5 { null or { Length: not 4 } => 0, [_, .. null or [_, not null], _] => 0, }; - _ = this switch // didn't test for [_, .. [_, null], _, _] // 8 + _ = this switch // didn't test for [_, .. [_, null], _, _] // 6 { null or { Length: not 5 } => 0, [_, .. null or [_, not null], _, _] => 0, }; - _ = this switch // didn't test for [_, .. [_, null, _], _] // 9 + _ = this switch // didn't test for [_, .. [_, null, _], _] // 7 { null or { Length: not 5 } => 0, [_, .. null or [_, not null, _], _] => 0, }; - _ = this switch // didn't test for [.. null, _] // we're trying to construct an example with Length=1 but a null slice // 10 + _ = this switch // didn't test for [.. null, _] but the slice is assumed not-null { null or { Length: not 1 } => 0, [.. { Length: 1 }] => 0, @@ -4763,36 +5063,27 @@ public void M() // Note: we don't try to explain nested slice patterns right now so all these just produce a fallback example var compilation = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); compilation.VerifyEmitDiagnostics( - // (20,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // we didn't test for [.. null] but we're looking for an example with Length=1. // 1 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(20, 18), - // (27,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // didn't test for [.. [not null]] // // 2 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(27, 18), - // (33,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // didn't test for [.. [not null]] // // 3 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(33, 18), - // (40,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // didn't test for [.. null, _] // we're trying to construct an example with Length=1, the slice may not be null // 4 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(40, 18), - // (46,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // didn't test for [_, .. null, _, _, _] // we're trying to construct an example with Length=4, the slice may not be null // 5 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(46, 18), - // (52,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // we should consider this switch exhaustive // 6 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(52, 18), - // (58,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // didn't test for [_, .. [_, null], _] // 7 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(58, 18), - // (64,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // didn't test for [_, .. [_, null], _, _] // 8 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(64, 18), - // (70,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // didn't test for [_, .. [_, null, _], _] // 9 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(70, 18), - // (76,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. - // _ = this switch // didn't test for [.. null, _] // we're trying to construct an example with Length=1 but a null slice // 10 - Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(76, 18) + // (27,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. + // _ = this switch // didn't test for [.. [not null]] // 1 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(27, 18), + // (33,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. + // _ = this switch // didn't test for [.. [not null]] // 2 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(33, 18), + // (40,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. + // _ = this switch // didn't test for [.. null, _] // we're trying to construct an example with Length=1, the slice may not be null // 3 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(40, 18), + // (46,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. + // _ = this switch // didn't test for [_, .. null, _, _, _] // we're trying to construct an example with Length=4, the slice may not be null // 4 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(46, 18), + // (58,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. + // _ = this switch // didn't test for [_, .. [_, null], _] // 5 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(58, 18), + // (64,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. + // _ = this switch // didn't test for [_, .. [_, null], _, _] // 6 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(64, 18), + // (70,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '_' is not covered. + // _ = this switch // didn't test for [_, .. [_, null, _], _] // 7 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("_").WithLocation(70, 18) ); } @@ -5051,7 +5342,8 @@ void M2() "; var compilation = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); compilation.VerifyEmitDiagnostics(); - var verifier = CompileAndVerify(compilation, expectedOutput: "(item value, rest value)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + var verifier = CompileAndVerify(compilation, expectedOutput: "(item value, rest value)", verify: Verification.FailsILVerify); verifier.VerifyIL("C.M", @" { @@ -5139,7 +5431,8 @@ void M2() "; var compilation = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); compilation.VerifyEmitDiagnostics(); - var verifier = CompileAndVerify(compilation, expectedOutput: "(item value, rest value)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + var verifier = CompileAndVerify(compilation, expectedOutput: "(item value, rest value)", verify: Verification.FailsILVerify); verifier.VerifyIL("C.M", @" { @@ -5228,7 +5521,8 @@ static void Main() Console.Write((x, y)); } }"; - CompileAndVerify(new[] { src, TestSources.Index, TestSources.Range }, expectedOutput: "Index Range (42, 43)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(new[] { src, TestSources.Index, TestSources.Range }, expectedOutput: "Index Range (42, 43)", verify: Verification.FailsILVerify); } [Fact] @@ -5267,7 +5561,8 @@ public void SlicePattern_String() System.Console.Write((first, rest).ToString()); } "; - CompileAndVerify(new[] { src, TestSources.Index, TestSources.Range }, expectedOutput: "(a, bc)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(new[] { src, TestSources.Index, TestSources.Range }, expectedOutput: "(a, bc)", verify: Verification.FailsILVerify); } [Fact] @@ -6178,45 +6473,70 @@ void Test(int[] a) { Length: not 1 } => 0, [<0, ..] => 0, [..[>= 0]] or [..null] => 1, - [_] => 2, // unreachable + [_] => 2, // unreachable 1 }; - _ = a switch // exhaustive + _ = a switch { { Length: not 1 } => 0, [<0, ..] => 0, [..[>= 0]] => 1, - [_] => 2, + [_] => 2, // unreachable 2 }; } }" + TestSources.GetSubArray; var comp = CreateCompilationWithIndexAndRange(src); comp.VerifyEmitDiagnostics( - // (11,13): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. - // [_] => 2, // unreachable - Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "[_]").WithLocation(11, 13)); - - VerifyDecisionDagDump(comp, + // (11,13): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. + // [_] => 2, // unreachable 1 + Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "[_]").WithLocation(11, 13), + // (18,13): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. + // [_] => 2, // unreachable 2 + Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "[_]").WithLocation(18, 13) + ); -@"[0]: t0 != null ? [1] : [12] + AssertEx.Multiple( + () => VerifyDecisionDagDump(comp, +@"[0]: t0 != null ? [1] : [11] [1]: t1 = t0.Length; [2] -[2]: t1 == 1 ? [3] : [11] +[2]: t1 == 1 ? [3] : [10] [3]: t2 = t0[0]; [4] [4]: t2 < 0 ? [5] : [6] [5]: leaf `[<0, ..] => 0` [6]: t3 = DagSliceEvaluation(t0); [7] -[7]: t3 != null ? [8] : [10] -[8]: t4 = t3.Length; [9] -[9]: t5 = t3[0]; [10] -[10]: leaf `[..[>= 0]] or [..null] => 1` -[11]: leaf `{ Length: not 1 } => 0` -[12]: leaf `a switch +[7]: t4 = t3.Length; [8] +[8]: t5 = t3[0]; [9] +[9]: leaf `[..[>= 0]] or [..null] => 1` +[10]: leaf `{ Length: not 1 } => 0` +[11]: leaf `a switch { { Length: not 1 } => 0, [<0, ..] => 0, [..[>= 0]] or [..null] => 1, - [_] => 2, // unreachable + [_] => 2, // unreachable 1 }` -"); +", index: 0), + + () => VerifyDecisionDagDump(comp, +@"[0]: t0 != null ? [1] : [11] +[1]: t1 = t0.Length; [2] +[2]: t1 == 1 ? [3] : [10] +[3]: t2 = t0[0]; [4] +[4]: t2 < 0 ? [5] : [6] +[5]: leaf `[<0, ..] => 0` +[6]: t3 = DagSliceEvaluation(t0); [7] +[7]: t4 = t3.Length; [8] +[8]: t5 = t3[0]; [9] +[9]: leaf `[..[>= 0]] => 1` +[10]: leaf `{ Length: not 1 } => 0` +[11]: leaf `a switch + { + { Length: not 1 } => 0, + [<0, ..] => 0, + [..[>= 0]] => 1, + [_] => 2, // unreachable 2 + }` +", index: 1) + ); } [Fact] @@ -6662,55 +6982,45 @@ void Test(int[] a) "); } - [Theory] - [CombinatorialData] - public void Subsumption_Slice_00( - [CombinatorialValues( - "[1,2,3]", - "[1,2,3,..[]]", - "[1,2,..[],3]", - "[1,..[],2,3]", - "[..[],1,2,3]", - "[1,..[2,3]]", - "[..[1,2],3]", - "[..[1,2,3]]", - "[..[..[1,2,3]]]", - "[..[1,2,3,..[]]]", - "[..[1,2,..[],3]]", - "[..[1,..[],2,3]]", - "[..[..[],1,2,3]]", - "[..[1,..[2,3]]]", - "[..[..[1,2],3]]", - "[1, ..[2], 3]", - "[1, ..[2, ..[3]]]", - "[1, ..[2, ..[], 3]]")] - string case1, - [CombinatorialValues( - "[1,2,3]", - "[1,2,3,..[]]", - "[1,2,..[],3]", - "[1,..[],2,3]", - "[..[],1,2,3]", - "[1,..[2,3]]", - "[..[1,2],3]", - "[..[1,2,3]]", - "[..[..[1,2,3]]]", - "[..[1,2,3,..[]]]", - "[..[1,2,..[],3]]", - "[..[1,..[],2,3]]", - "[..[..[],1,2,3]]", - "[..[1,..[2,3]]]", - "[..[..[1,2],3]]", - "[1, ..[2], 3]", - "[1, ..[2, ..[3]]]", - "[1, ..[2, ..[], 3]]")] - string case2) + [Fact] + public void Subsumption_Slice_00() { - var src = @" -using System; + const int Count = 18; + var cases = new string[Count] + { + "[1,2,3]", + "[1,2,3,..[]]", + "[1,2,..[],3]", + "[1,..[],2,3]", + "[..[],1,2,3]", + "[1,..[2,3]]", + "[..[1,2],3]", + "[..[1,2,3]]", + "[..[..[1,2,3]]]", + "[..[1,2,3,..[]]]", + "[..[1,2,..[],3]]", + "[..[1,..[],2,3]]", + "[..[..[],1,2,3]]", + "[..[1,..[2,3]]]", + "[..[..[1,2],3]]", + "[1, ..[2], 3]", + "[1, ..[2, ..[3]]]", + "[1, ..[2, ..[], 3]]" + }; + + // testing every possible combination takes too long, + // covering a random subset instead. + var r = new Random(); + for (int i = 0; i < 50; i++) + { + var case1 = cases[r.Next(Count)]; + var case2 = cases[r.Next(Count)]; + var type = r.Next(2) == 0 ? "System.Span" : "int[]"; + + var src = @" class C { - void Test(Span a) + void Test(" + type + @" a) { switch (a) { @@ -6720,11 +7030,12 @@ void Test(Span a) } } }"; - var comp = CreateCompilationWithIndexAndRangeAndSpan(src, parseOptions: TestOptions.RegularWithListPatterns); - comp.VerifyEmitDiagnostics( - // (10,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match. - Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, case2).WithLocation(10, 18) - ); + var comp = CreateCompilationWithIndexAndRangeAndSpan(new[] { src, TestSources.GetSubArray }, parseOptions: TestOptions.RegularWithListPatterns); + comp.VerifyEmitDiagnostics( + // (9,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match. + Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, case2).WithLocation(9, 18) + ); + } } [Fact] @@ -6749,6 +7060,73 @@ public static void Test(System.Span a) Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "[..[var v]]").WithLocation(9, 18)); } + [Fact] + public void Subsumption_Slice_02() + { + var source = @" +using System; + +IOuter outer = null; +switch (outer) +{ + case [..[..[10],20]]: + break; + case [..[10],20]: // 1 + break; +} + +interface IOuter +{ + int Length { get; } + IInner Slice(int a, int b); + object this[int i] { get; } +} +interface IInner +{ + int Count { get; } + IOuter this[Range r] { get; } + object this[Index i] { get; } +} +"; + var comp = CreateCompilationWithIndexAndRangeAndSpan(new[] { source, TestSources.GetSubArray }, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (9,10): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match. + // case [..[10],20]: // 1 + Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "[..[10],20]").WithLocation(9, 10) + ); + } + + [Fact] + public void Subsumption_Slice_03() + { + var source = @" +#nullable enable +class C +{ + public int Length => 3; + public int this[int i] => 0; + public int[]? Slice(int i, int j) => null; + + public static void Main() + { + switch (new C()) + { + case [.. {}]: + break; + case [.. null]: + break; + } + } +} +"; + var compilation = CreateCompilationWithIndexAndRange(source, options: TestOptions.ReleaseExe); + compilation.VerifyEmitDiagnostics( + // (15,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match. + // case [.. null]: + Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "[.. null]").WithLocation(15, 18) + ); + } + [Fact] public void Exhaustiveness_01() { @@ -7068,7 +7446,8 @@ public string M() } } "; - var verifier = CompileAndVerify(new[] { source, TestSources.Index }, options: TestOptions.DebugDll); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + var verifier = CompileAndVerify(new[] { source, TestSources.Index }, options: TestOptions.DebugDll, verify: Verification.FailsILVerify); verifier.VerifyIL("C.M", @" { // Code size 105 (0x69) @@ -7165,7 +7544,8 @@ public string M() } } "; - var verifier = CompileAndVerify(new[] { source, TestSources.Index }); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + var verifier = CompileAndVerify(new[] { source, TestSources.Index }, verify: Verification.FailsILVerify); verifier.VerifyIL("C.M", @" { // Code size 78 (0x4e) @@ -7314,7 +7694,8 @@ public void M() ); compilation = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); - var verifier = CompileAndVerify(compilation, expectedOutput: "(2, 3)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + var verifier = CompileAndVerify(compilation, expectedOutput: "(2, 3)", verify: Verification.FailsILVerify); verifier.VerifyDiagnostics(); // Note: no Index or Range involved verifier.VerifyIL("C.M", @" @@ -7560,7 +7941,8 @@ class C "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "(42, 42)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(comp, expectedOutput: "(42, 42)", verify: Verification.FailsILVerify); } [Fact] @@ -7606,7 +7988,8 @@ class C "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "(42, 42)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(comp, expectedOutput: "(42, 42)", verify: Verification.FailsILVerify); } [Fact] @@ -7620,7 +8003,8 @@ public void Simple_String() "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "(4, 2)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(comp, expectedOutput: "(4, 2)", verify: Verification.FailsILVerify); } [Fact] @@ -7635,7 +8019,8 @@ public void Simple_Array() "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "(4, 2)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(comp, expectedOutput: "(4, 2)", verify: Verification.FailsILVerify); } [Theory] @@ -7656,7 +8041,8 @@ public void Simple_Array_VerifyIndexMaths(string data, string pattern, string el "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "(4, 4)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(comp, expectedOutput: "(4, 4)", verify: Verification.FailsILVerify); } [Fact] @@ -7677,7 +8063,8 @@ class C "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "(42, 42)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(comp, expectedOutput: "(42, 42)", verify: Verification.FailsILVerify); } [Fact] @@ -7698,7 +8085,8 @@ class C "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "(42, 42)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(comp, expectedOutput: "(42, 42)", verify: Verification.FailsILVerify); } [Fact] @@ -7712,7 +8100,8 @@ public void Simple_String_Slice() "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "42"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(comp, expectedOutput: "42", verify: Verification.FailsILVerify); } [Fact, WorkItem(57728, "https://github.com/dotnet/roslyn/issues/57728")] @@ -7733,7 +8122,8 @@ public static void Main() "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range, TestSources.GetSubArray }, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics(); - var verifier = CompileAndVerify(comp, expectedOutput: "(4, 2, 4, 2)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + var verifier = CompileAndVerify(comp, expectedOutput: "(4, 2, 4, 2)", verify: Verification.FailsILVerify); // we use Array.Length to get the length, but should be using ldlen // Tracked by https://github.com/dotnet/roslyn/issues/57728 verifier.VerifyIL("C.Main", @" @@ -7825,7 +8215,8 @@ public void Simple_Array_Slice_VerifyRangeMaths(string data, string pattern, str "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range, TestSources.GetSubArray }); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "(4, 2, 2, 4, 2, 2)"); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of 'System.Index', Expected = address of 'System.Index' } + CompileAndVerify(comp, expectedOutput: "(4, 2, 2, 4, 2, 2)", verify: Verification.FailsILVerify); } [Fact] @@ -7846,7 +8237,8 @@ public int M(int[] a) } "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range, TestSources.GetSubArray }, options: TestOptions.ReleaseDll); - var verifier = CompileAndVerify(comp).VerifyDiagnostics(); + // ILVerify: Unexpected type on the stack. { Offset = 20, Found = readonly address of '[...]System.Index', Expected = address of '[...]System.Index' } + var verifier = CompileAndVerify(comp, verify: Verification.FailsILVerify).VerifyDiagnostics(); verifier.VerifyIL("C.M", @" { @@ -7922,7 +8314,7 @@ class C : Interface } "; var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); - var verifier = CompileAndVerify(comp, expectedOutput: "(42, 43)"); + var verifier = CompileAndVerify(comp, expectedOutput: "(42, 43)", verify: Verification.FailsILVerify); verifier.VerifyDiagnostics(); } @@ -7974,7 +8366,7 @@ public void ListPattern_NullTestOnSlice() switch (a) { case [..[1],2,3]: - case [1,2,3]: // no error + case [1,2,3]: // error break; } "; @@ -7982,7 +8374,10 @@ public void ListPattern_NullTestOnSlice() comp.VerifyEmitDiagnostics( // (7,10): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match. // case [1,2,3]: // error - Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "[1,2,3]").WithLocation(7, 10) + Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "[1,2,3]").WithLocation(7, 10), + // (15,10): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match. + // case [1,2,3]: // error + Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "[1,2,3]").WithLocation(15, 10) ); } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs new file mode 100644 index 0000000000000..dcc4bf3ff48d6 --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs @@ -0,0 +1,1276 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics; + +public partial class RawInterpolationTests : CompilingTestBase +{ + [Fact] + public void TestSimpleInterp() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + var number = 8675309; + Console.WriteLine($""""""Jenny don\'t change your number { number }.""""""); + Console.WriteLine($""""""Jenny don\'t change your number { number , -12 }.""""""); + Console.WriteLine($""""""Jenny don\'t change your number { number , 12 }.""""""); + Console.WriteLine($""""""Jenny don\'t change your number { number :###-####}.""""""); + Console.WriteLine($""""""Jenny don\'t change your number { number , -12 :###-####}.""""""); + Console.WriteLine($""""""Jenny don\'t change your number { number , 12 :###-####}.""""""); + Console.WriteLine($""""""{number}""""""); + } +}"; + string expectedOutput = +@"Jenny don\'t change your number 8675309. +Jenny don\'t change your number 8675309 . +Jenny don\'t change your number 8675309. +Jenny don\'t change your number 867-5309. +Jenny don\'t change your number 867-5309 . +Jenny don\'t change your number 867-5309. +8675309"; + CompileAndVerify(source, expectedOutput: expectedOutput); + } + + [Fact] + public void TestOnlyInterp() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + var number = 8675309; + Console.WriteLine($""""""{number}""""""); + } +}"; + string expectedOutput = +@"8675309"; + CompileAndVerify(source, expectedOutput: expectedOutput); + } + + [Fact] + public void TestDoubleInterp01() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + var number = 8675309; + Console.WriteLine($""""""{number}{number}""""""); + } +}"; + string expectedOutput = +@"86753098675309"; + CompileAndVerify(source, expectedOutput: expectedOutput); + } + + [Fact] + public void TestDoubleInterp02() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + var number = 8675309; + Console.WriteLine($""""""Jenny don\'t change your number { number :###-####} { number :###-####}.""""""); + } +}"; + string expectedOutput = +@"Jenny don\'t change your number 867-5309 867-5309."; + CompileAndVerify(source, expectedOutput: expectedOutput); + } + + [Fact] + public void TestEmptyInterp() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + Console.WriteLine($""""""Jenny don\'t change your number { /*trash*/ }.""""""); + } +}"; + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (5,75): error CS1733: Expected expression + // Console.WriteLine($"""Jenny don\'t change your number { /*trash*/ }."""); + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(5, 75)); + } + + [Fact] + public void TestHalfOpenInterp01() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + Console.WriteLine($""""""Jenny don\'t change your number { """"""); + } +}"; + // too many diagnostics perhaps, but it starts the right way. + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (5,70): error CS8997: Unterminated raw string literal + // Console.WriteLine($"""Jenny don\'t change your number { """); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, @" +").WithLocation(5, 70), + // (6,5): error CS8997: Unterminated raw string literal + // } + Diagnostic(ErrorCode.ERR_UnterminatedRawString, "}").WithLocation(6, 5), + // (6,6): error CS1026: ) expected + // } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 6), + // (6,6): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 6), + // (7,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 2)); + } + + [Fact] + public void TestHalfOpenInterp02() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + Console.WriteLine($""""""Jenny don\'t change your number { 8675309 // """"""); + } +}"; + // too many diagnostics perhaps, but it starts the right way. + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (6,5): error CS8997: Unterminated raw string literal + // } + Diagnostic(ErrorCode.ERR_UnterminatedRawString, "}").WithLocation(6, 5), + // (6,6): error CS1026: ) expected + // } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 6), + // (6,6): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 6), + // (7,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 2)); + } + + [Fact] + public void TestHalfOpenInterp03() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + Console.WriteLine($""""""Jenny don\'t change your number { 8675309 /* """"""); + } +}"; + // too many diagnostics perhaps, but it starts the right way. + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (5,63): error CS8076: Missing close delimiter '}' for interpolated expression started with '{'. + // Console.WriteLine($"""Jenny don\'t change your number { 8675309 /* """); + Diagnostic(ErrorCode.ERR_UnclosedExpressionHole, "{").WithLocation(5, 63), + // (5,73): error CS1035: End-of-file found, '*/' expected + // Console.WriteLine($"""Jenny don\'t change your number { 8675309 /* """); + Diagnostic(ErrorCode.ERR_OpenEndedComment, "").WithLocation(5, 73), + // (7,2): error CS1026: ) expected + // } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 2), + // (7,2): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(7, 2), + // (7,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 2), + // (7,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 2)); + } + + [Fact] + public void LambdaInInterp() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + //Console.WriteLine(""""""jenny {0:(408) ###-####}"""""", new object[] { ((Func)(() => { return number; })).Invoke() }); + Console.WriteLine($""""""jenny { ((Func)(() => { return number; })).Invoke() :(408) ###-####}""""""); + } + + static int number = 8675309; + } +"; + string expectedOutput = @"jenny (408) 867-5309"; + CompileAndVerify(source, expectedOutput: expectedOutput); + } + + [Fact] + public void OneLiteral() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + Console.WriteLine( $""""""Hello"""""" ); + } +}"; + string expectedOutput = @"Hello"; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput); + verifier.VerifyIL("Program.Main", @" +{ + // Code size 11 (0xb) + .maxstack 1 + IL_0000: ldstr ""Hello"" + IL_0005: call ""void System.Console.WriteLine(string)"" + IL_000a: ret +} +"); + } + + [Fact] + public void OneInsert() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + var hello = $""""""Hello""""""; + Console.WriteLine( $""""""{hello}"""""" ); + } +}"; + string expectedOutput = @"Hello"; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput); + verifier.VerifyIL("Program.Main", @" +{ + // Code size 20 (0x14) + .maxstack 2 + IL_0000: ldstr ""Hello"" + IL_0005: dup + IL_0006: brtrue.s IL_000e + IL_0008: pop + IL_0009: ldstr """" + IL_000e: call ""void System.Console.WriteLine(string)"" + IL_0013: ret +} +"); + } + + [Fact] + public void TwoInserts() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + var hello = $""""""Hello""""""; + var world = $""""""world"""""" ; + Console.WriteLine( $""""""{hello}, { world }."""""" ); + } +}"; + string expectedOutput = @"Hello, world."; + CompileAndVerify(source, expectedOutput: expectedOutput); + } + + [Fact] + public void TwoInserts02() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + var hello = ""Hello""; + var world = ""world""; + Console.WriteLine( $"""""" + { + hello + }, +{ + world }. + """""" ); + } +}"; + string expectedOutput = @"Hello, +world."; + CompileAndVerify(source, expectedOutput: expectedOutput); + } + + [Fact, WorkItem(306, "https://github.com/dotnet/roslyn/issues/306"), WorkItem(308, "https://github.com/dotnet/roslyn/issues/308")] + public void DynamicInterpolation() + { + string source = +@"using System; +using System.Linq.Expressions; +class Program +{ + static void Main(string[] args) + { + dynamic nil = null; + dynamic a = new string[] {""""""Hello"""""", """"""world""""""}; + Console.WriteLine($""""""<{nil}>""""""); + Console.WriteLine($""""""<{a}>""""""); + } + Expression> M(dynamic d) { + return () => $""""""Dynamic: {d}""""""; + } +}"; + string expectedOutput = @"<> +"; + var verifier = CompileAndVerify(source, new[] { CSharpRef }, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void UnclosedInterpolation01() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + Console.WriteLine( $""""""{"""""" ); + } +}"; + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (6,39): error CS8997: Unterminated raw string literal + // Console.WriteLine( $"""{""" ); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, @" +").WithLocation(6, 39), + // (7,5): error CS8997: Unterminated raw string literal + // } + Diagnostic(ErrorCode.ERR_UnterminatedRawString, "}").WithLocation(7, 5), + // (7,6): error CS1026: ) expected + // } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 6), + // (7,6): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(7, 6), + // (8,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(8, 2)); + } + + [Fact] + public void UnclosedInterpolation02() + { + string source = +@"class Program +{ + static void Main(string[] args) + { + var x = $"""""";"; + // The precise error messages are not important, but this must be an error. + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (5,21): error CS8997: Unterminated raw string literal + // var x = $"""; + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(5, 21), + // (5,22): error CS1002: ; expected + // var x = $"""; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(5, 22), + // (5,22): error CS1513: } expected + // var x = $"""; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 22), + // (5,22): error CS1513: } expected + // var x = $"""; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 22)); + } + + [Fact] + public void EmptyFormatSpecifier() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + Console.WriteLine( $""""""{3:}"""""" ); + } +}"; + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (6,34): error CS8089: Empty format specifier. + // Console.WriteLine( $"""{3:}""" ); + Diagnostic(ErrorCode.ERR_EmptyFormatSpecifier, ":").WithLocation(6, 34)); + } + + [Fact] + public void TrailingSpaceInFormatSpecifier() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + Console.WriteLine( $""""""{3:d }"""""" ); + } +}"; + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (6,34): error CS8088: A format specifier may not contain trailing whitespace. + // Console.WriteLine( $"""{3:d }""" ); + Diagnostic(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, ":d ").WithLocation(6, 34)); + } + + [Fact] + public void TrailingSpaceInFormatSpecifier02() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + Console.WriteLine( $""""""{3:d +}"""""" ); + } +}"; + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (6,34): error CS8088: A format specifier may not contain trailing whitespace. + // Console.WriteLine( $"""{3:d + Diagnostic(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, @":d +").WithLocation(6, 34)); + } + + [Fact] + public void MissingInterpolationExpression01() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + Console.WriteLine( $""""""{ }"""""" ); + } +}"; + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (6,34): error CS1733: Expected expression + // Console.WriteLine( $"""{ }""" ); + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 34)); + } + + [Fact] + public void MissingInterpolationExpression02() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + Console.WriteLine( $""""""{ }"""""" ); + } +}"; + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (6,34): error CS1733: Expected expression + // Console.WriteLine( $"""{ }""" ); + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 34)); + } + + [Fact] + public void MissingInterpolationExpression03() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + Console.WriteLine( "; + var normal = "$\"\"\""; + // ensure reparsing of interpolated string token is precise in error scenarios (assertions do not fail) + Assert.True(SyntaxFactory.ParseSyntaxTree(source + normal).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)); + Assert.True(SyntaxFactory.ParseSyntaxTree(source + normal + " ").GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)); + Assert.True(SyntaxFactory.ParseSyntaxTree(source + normal + "{").GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)); + Assert.True(SyntaxFactory.ParseSyntaxTree(source + normal + "{ ").GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)); + } + + [Fact] + public void MisplacedNewline01() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + var s = $""""""{ @"" +"" } + """"""; + } +}"; + // The precise error messages are not important, but this must be an error. + Assert.True(SyntaxFactory.ParseSyntaxTree(source).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)); + } + + [Fact] + public void MisplacedNewline02() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + var s = $""""""{ @"" +""} + """"""; + } +}"; + // The precise error messages are not important, but this must be an error. + Assert.True(SyntaxFactory.ParseSyntaxTree(source).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)); + } + + [Fact] + public void PreprocessorInsideInterpolation() + { + string source = +@"class Program +{ + static void Main() + { + var s = $""""""{ +#region : +#endregion +0 +}""""""; + } +}"; + // The precise error messages are not important, but this must be an error. + Assert.True(SyntaxFactory.ParseSyntaxTree(source).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)); + } + + [Fact] + public void EscapesAreNotEscapes() + { + string source = +@"class Program +{ + static void Main() + { + var s1 = $"""""" \u007B """"""; + var s2 = $"""""" \u007D""""""; + } +}"; + CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + } + + [Fact, WorkItem(1119878, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1119878")] + public void NoFillIns01() + { + string source = +@"class Program +{ + static void Main() + { + System.Console.Write($$""""""{ x }""""""); + System.Console.WriteLine($""""""This is a test""""""); + } +}"; + string expectedOutput = @"{ x }This is a test"; + CompileAndVerify(source, expectedOutput: expectedOutput); + } + + [Fact] + public void BadAlignment() + { + string source = +@"class Program +{ + static void Main() + { + var s = $""""""{1,1E10}""""""; + var t = $""""""{1,(int)1E10}""""""; + } +}"; + CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + // (5,24): error CS0266: Cannot implicitly convert type 'double' to 'int'. An explicit conversion exists (are you missing a cast?) + // var s = $"""{1,1E10}"""; + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "1E10").WithArguments("double", "int").WithLocation(5, 24), + // (5,24): error CS0150: A constant value is expected + // var s = $"""{1,1E10}"""; + Diagnostic(ErrorCode.ERR_ConstantExpected, "1E10").WithLocation(5, 24), + // (6,24): error CS0221: Constant value '10000000000' cannot be converted to a 'int' (use 'unchecked' syntax to override) + // var t = $"""{1,(int)1E10}"""; + Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "(int)1E10").WithArguments("10000000000", "int").WithLocation(6, 24), + // (6,24): error CS0150: A constant value is expected + // var t = $"""{1,(int)1E10}"""; + Diagnostic(ErrorCode.ERR_ConstantExpected, "(int)1E10").WithLocation(6, 24)); + } + + [Fact] + public void NestedInterpolated() + { + string source = +@"using System; +class Program +{ + static void Main(string[] args) + { + var s = $""""""{$""""""{1}""""""}""""""; + Console.WriteLine(s); + } + }"; + string expectedOutput = @"1"; + CompileAndVerify(source, expectedOutput: expectedOutput); + } + + // Since the platform type System.FormattableString is not yet in our platforms (at the + // time of writing), we explicitly include the required platform types into the sources under test. + private const string formattableString = @" +/*============================================================ +** +** Class: FormattableString +** +** +** Purpose: implementation of the FormattableString +** class. +** +===========================================================*/ +namespace System +{ + /// + /// A composite format string along with the arguments to be formatted. An instance of this + /// type may result from the use of the C# or VB language primitive ""interpolated string"". + /// + public abstract class FormattableString : IFormattable + { + /// + /// The composite format string. + /// + public abstract string Format { get; } + + /// + /// Returns an object array that contains zero or more objects to format. Clients should not + /// mutate the contents of the array. + /// + public abstract object[] GetArguments(); + + /// + /// The number of arguments to be formatted. + /// + public abstract int ArgumentCount { get; } + + /// + /// Returns one argument to be formatted from argument position . + /// + public abstract object GetArgument(int index); + + /// + /// Format to a string using the given culture. + /// + public abstract string ToString(IFormatProvider formatProvider); + + string IFormattable.ToString(string ignored, IFormatProvider formatProvider) + { + return ToString(formatProvider); + } + + /// + /// Format the given object in the invariant culture. This static method may be + /// imported in C# by + /// + /// using static System.FormattableString; + /// . + /// Within the scope + /// of that import directive an interpolated string may be formatted in the + /// invariant culture by writing, for example, + /// + /// Invariant($""{{ lat = {latitude}; lon = {longitude} }}"") + /// + /// + public static string Invariant(FormattableString formattable) + { + if (formattable == null) + { + throw new ArgumentNullException(""formattable""); + } + + return formattable.ToString(Globalization.CultureInfo.InvariantCulture); + } + + public override string ToString() + { + return ToString(Globalization.CultureInfo.CurrentCulture); + } + } +} + + +/*============================================================ +** +** Class: FormattableStringFactory +** +** +** Purpose: implementation of the FormattableStringFactory +** class. +** +===========================================================*/ +namespace System.Runtime.CompilerServices +{ + /// + /// A factory type used by compilers to create instances of the type . + /// + public static class FormattableStringFactory + { + /// + /// Create a from a composite format string and object + /// array containing zero or more objects to format. + /// + public static FormattableString Create(string format, params object[] arguments) + { + if (format == null) + { + throw new ArgumentNullException(""format""); + } + + if (arguments == null) + { + throw new ArgumentNullException(""arguments""); + } + + return new ConcreteFormattableString(format, arguments); + } + + private sealed class ConcreteFormattableString : FormattableString + { + private readonly string _format; + private readonly object[] _arguments; + + internal ConcreteFormattableString(string format, object[] arguments) + { + _format = format; + _arguments = arguments; + } + + public override string Format { get { return _format; } } + public override object[] GetArguments() { return _arguments; } + public override int ArgumentCount { get { return _arguments.Length; } } + public override object GetArgument(int index) { return _arguments[index]; } + public override string ToString(IFormatProvider formatProvider) { return string.Format(formatProvider, Format, _arguments); } + } + } +} +"; + + [Fact] + public void TargetType01() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + IFormattable f = $""""""test""""""; + Console.Write(f is System.FormattableString); + } +}"; + CompileAndVerify(source + formattableString, expectedOutput: "True"); + } + + [Fact] + public void TargetType02() + { + string source = +@"using System; +interface I1 { void M(String s); } +interface I2 { void M(FormattableString s); } +interface I3 { void M(IFormattable s); } +interface I4 : I1, I2 {} +interface I5 : I1, I3 {} +interface I6 : I2, I3 {} +interface I7 : I1, I2, I3 {} +class C : I1, I2, I3, I4, I5, I6, I7 +{ + public void M(String s) { Console.Write(1); } + public void M(FormattableString s) { Console.Write(2); } + public void M(IFormattable s) { Console.Write(3); } +} +class Program { + public static void Main(string[] args) + { + C c = new C(); + ((I1)c).M($"""""" """"""); + ((I2)c).M($"""""" """"""); + ((I3)c).M($"""""" """"""); + ((I4)c).M($"""""" """"""); + ((I5)c).M($"""""" """"""); + ((I6)c).M($"""""" """"""); + ((I7)c).M($"""""" """"""); + ((C)c).M($"""""" """"""); + } +}"; + CompileAndVerify(source + formattableString, expectedOutput: "12311211"); + } + + [Fact] + public void MissingHelper() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + IFormattable f = $""""""test""""""; + } +}"; + CreateCompilationWithMscorlib40(source).VerifyEmitDiagnostics( + // (5,26): error CS0518: Predefined type 'System.Runtime.CompilerServices.FormattableStringFactory' is not defined or imported + // IFormattable f = $"""test"""; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"$""""""test""""""").WithArguments("System.Runtime.CompilerServices.FormattableStringFactory").WithLocation(5, 26)); + } + + [Fact] + public void AsyncInterp() + { + string source = +@"using System; +using System.Threading.Tasks; +class Program { + public static void Main(string[] args) + { + Task hello = Task.FromResult(""""""Hello""""""); + Task world = Task.FromResult(""""""world""""""); + M(hello, world).Wait(); + } + public static async Task M(Task hello, Task world) + { + Console.WriteLine($""""""{ await hello }, { await world }!""""""); + } +}"; + CompileAndVerify( + source, references: new[] { MscorlibRef_v4_0_30316_17626, SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929 }, expectedOutput: "Hello, world!", targetFramework: TargetFramework.Empty); + } + + [Fact] + public void AlignmentExpression() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + Console.WriteLine($""""""X = { 123 , -(3+4) }.""""""); + } +}"; + CompileAndVerify(source + formattableString, expectedOutput: "X = 123 ."); + } + + [Fact] + public void AlignmentMagnitude() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + Console.WriteLine($""""""X = { 123 , (32768) }.""""""); + Console.WriteLine($""""""X = { 123 , -(32768) }.""""""); + Console.WriteLine($""""""X = { 123 , (32767) }.""""""); + Console.WriteLine($""""""X = { 123 , -(32767) }.""""""); + Console.WriteLine($""""""X = { 123 , int.MaxValue }.""""""); + Console.WriteLine($""""""X = { 123 , int.MinValue }.""""""); + } +}"; + CreateCompilation(source).VerifyDiagnostics( + // (5,44): warning CS8094: Alignment value 32768 has a magnitude greater than 32767 and may result in a large formatted string. + // Console.WriteLine($"""X = { 123 , (32768) }."""); + Diagnostic(ErrorCode.WRN_AlignmentMagnitude, "32768").WithArguments("32768", "32767").WithLocation(5, 44), + // (6,43): warning CS8094: Alignment value -32768 has a magnitude greater than 32767 and may result in a large formatted string. + // Console.WriteLine($"""X = { 123 , -(32768) }."""); + Diagnostic(ErrorCode.WRN_AlignmentMagnitude, "-(32768)").WithArguments("-32768", "32767").WithLocation(6, 43), + // (9,43): warning CS8094: Alignment value 2147483647 has a magnitude greater than 32767 and may result in a large formatted string. + // Console.WriteLine($"""X = { 123 , int.MaxValue }."""); + Diagnostic(ErrorCode.WRN_AlignmentMagnitude, "int.MaxValue").WithArguments("2147483647", "32767").WithLocation(9, 43), + // (10,43): warning CS8094: Alignment value -2147483648 has a magnitude greater than 32767 and may result in a large formatted string. + // Console.WriteLine($"""X = { 123 , int.MinValue }."""); + Diagnostic(ErrorCode.WRN_AlignmentMagnitude, "int.MinValue").WithArguments("-2147483648", "32767").WithLocation(10, 43)); + } + + [WorkItem(1097388, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097388")] + [Fact] + public void InterpolationExpressionMustBeValue01() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + Console.WriteLine($""""""X = { String }.""""""); + Console.WriteLine($""""""X = { null }.""""""); + } +}"; + CreateCompilation(source).VerifyDiagnostics( + // (5,37): error CS0119: 'string' is a type, which is not valid in the given context + // Console.WriteLine($"""X = { String }."""); + Diagnostic(ErrorCode.ERR_BadSKunknown, "String").WithArguments("string", "type").WithLocation(5, 37)); + } + + [Fact] + public void InterpolationExpressionMustBeValue02() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + Console.WriteLine($""""""X = { x=>3 }.""""""); + Console.WriteLine($""""""X = { Program.Main }.""""""); + Console.WriteLine($""""""X = { Program.Main(null) }.""""""); + } +}"; + + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( + // (5,37): error CS8917: The delegate type could not be inferred. + // Console.WriteLine($"""X = { x=>3 }."""); + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "x=>3").WithLocation(5, 37), + // (6,37): warning CS8974: Converting method group 'Main' to non-delegate type 'object'. Did you intend to invoke the method? + // Console.WriteLine($"""X = { Program.Main }."""); + Diagnostic(ErrorCode.WRN_MethGrpToNonDel, "Program.Main").WithArguments("Main", "object").WithLocation(6, 37), + // (7,37): error CS0029: Cannot implicitly convert type 'void' to 'object' + // Console.WriteLine($"""X = { Program.Main(null) }."""); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "Program.Main(null)").WithArguments("void", "object").WithLocation(7, 37)); + } + + [WorkItem(1097428, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097428")] + [Fact] + public void BadCorelib01() + { + var text = +@"namespace System +{ + public class Object { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { private Boolean m_value; Boolean Use(Boolean b) { m_value = b; return m_value; } } + public struct Int32 { private Int32 m_value; Int32 Use(Int32 b) { m_value = b; return m_value; } } + public struct Char { } + public class String { } + + internal class Program + { + public static void Main() + { + var s = $""""""X = { 1 } """"""; + } + } +}"; + CreateEmptyCompilation(text, options: TestOptions.DebugExe) + .VerifyEmitDiagnostics(new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "x.y"), + // (15,21): error CS0117: 'string' does not contain a definition for 'Format' + // var s = $"""X = { 1 } """; + Diagnostic(ErrorCode.ERR_NoSuchMember, @"$""""""X = { 1 } """"""").WithArguments("string", "Format").WithLocation(15, 21)); + } + + [WorkItem(1097428, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097428")] + [Fact] + public void BadCorelib02() + { + var text = +@"namespace System +{ + public class Object { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { private Boolean m_value; Boolean Use(Boolean b) { m_value = b; return m_value; } } + public struct Int32 { private Int32 m_value; Int32 Use(Int32 b) { m_value = b; return m_value; } } + public struct Char { } + public class String { + public static Boolean Format(string format, int arg) { return true; } + } + + internal class Program + { + public static void Main() + { + var s = $""""""X = { 1 } """"""; + } + } +}"; + CreateEmptyCompilation(text, options: TestOptions.DebugExe) + .VerifyEmitDiagnostics(new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "x.y"), + // (17,21): error CS0029: Cannot implicitly convert type 'bool' to 'string' + // var s = $"""X = { 1 } """; + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""""""X = { 1 } """"""").WithArguments("bool", "string").WithLocation(17, 21)); + } + + [Fact] + public void SillyCoreLib01() + { + var text = +@"namespace System +{ + interface IFormattable { } + namespace Runtime.CompilerServices { + public static class FormattableStringFactory { + public static Bozo Create(string format, int arg) { return new Bozo(); } + } + } + public class Object { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { private Boolean m_value; Boolean Use(Boolean b) { m_value = b; return m_value; } } + public struct Int32 { private Int32 m_value; Int32 Use(Int32 b) { m_value = b; return m_value; } } + public struct Char { } + public class String { + public static Bozo Format(string format, int arg) { return new Bozo(); } + } + public class FormattableString { + } + public class Bozo { + public static implicit operator string(Bozo bozo) { return ""zz""; } + public static implicit operator FormattableString(Bozo bozo) { return new FormattableString(); } + } + + internal class Program + { + public static void Main() + { + var s1 = $""""""X = { 1 } """"""; + FormattableString s2 = $""""""X = { 1 } """"""; + } + } +}"; + var comp = CreateEmptyCompilation(text, options: Test.Utilities.TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + var compilation = CompileAndVerify(comp, verify: Verification.Fails); + compilation.VerifyIL("System.Program.Main", +@"{ + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldstr ""X = {0} "" + IL_0005: ldc.i4.1 + IL_0006: call ""System.Bozo string.Format(string, int)"" + IL_000b: call ""string System.Bozo.op_Implicit(System.Bozo)"" + IL_0010: pop + IL_0011: ldstr ""X = {0} "" + IL_0016: ldc.i4.1 + IL_0017: call ""System.Bozo System.Runtime.CompilerServices.FormattableStringFactory.Create(string, int)"" + IL_001c: call ""System.FormattableString System.Bozo.op_Implicit(System.Bozo)"" + IL_0021: pop + IL_0022: ret +}"); + } + + [WorkItem(1097386, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097386")] + [Fact] + public void Syntax01() + { + var text = +@"using System; +class Program +{ + static void Main(string[] args) + { + var x = $""""""{ Math.Abs(value: 1):\}""""""; + var y = x; + } + } +"; + CreateCompilation(text).VerifyDiagnostics(); + } + + [WorkItem(1097941, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097941")] + [Fact] + public void Syntax02() + { + var text = +@"using S = System; +class C +{ + void M() + { + var x = $""""""{ (S: + } +}"; + // the precise diagnostics do not matter, as long as it is an error and not a crash. + Assert.True(SyntaxFactory.ParseSyntaxTree(text).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)); + } + + [WorkItem(1097386, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097386")] + [Fact] + public void Syntax03() + { + var text = +@"using System; +class Program +{ + static void Main(string[] args) + { + var x = $""""""{ Math.Abs(value: 1):}}""""""; + var y = x; + } + } +"; + CreateCompilation(text).VerifyDiagnostics( + // (6,41): error CS8089: Empty format specifier. + // var x = $"""{ Math.Abs(value: 1):}}"""; + Diagnostic(ErrorCode.ERR_EmptyFormatSpecifier, ":").WithLocation(6, 41), + // (6,43): error CS9007: Too many closing braces for raw string literal + // var x = $"""{ Math.Abs(value: 1):}}"""; + Diagnostic(ErrorCode.ERR_TooManyCloseBracesForRawString, "}").WithLocation(6, 43)); + } + + [WorkItem(1099105, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1099105")] + [Fact] + public void NoUnexpandedForm() + { + string source = +@"using System; +class Program { + public static void Main(string[] args) + { + string[] arr1 = new string[] { """"""xyzzy"""""" }; + object[] arr2 = arr1; + Console.WriteLine($""""""-{null}-""""""); + Console.WriteLine($""""""-{arr1}-""""""); + Console.WriteLine($""""""-{arr2}-""""""); + } +}"; + CompileAndVerify(source + formattableString, expectedOutput: +@"-- +-System.String[]- +-System.String[]-"); + } + + [WorkItem(1097386, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097386")] + [Fact] + public void Dynamic01() + { + var text = +@"class C +{ + const dynamic a = a; + string s = $""""""{0,a}""""""; +}"; + CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( + // (3,19): error CS0110: The evaluation of the constant value for 'C.a' involves a circular definition + // const dynamic a = a; + Diagnostic(ErrorCode.ERR_CircConstValue, "a").WithArguments("C.a").WithLocation(3, 19), + // (3,23): error CS0134: 'C.a' is of type 'dynamic'. A const field of a reference type other than string can only be initialized with null. + // const dynamic a = a; + Diagnostic(ErrorCode.ERR_NotNullConstRefField, "a").WithArguments("C.a", "dynamic").WithLocation(3, 23), + // (4,23): error CS0150: A constant value is expected + // string s = $"""{0,a}"""; + Diagnostic(ErrorCode.ERR_ConstantExpected, "a").WithLocation(4, 23)); + } + + [WorkItem(1099238, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1099238")] + [Fact] + public void Syntax04() + { + var text = +@"using System; +using System.Linq.Expressions; + +class Program +{ + static void Main() + { + Expression> e = () => $""""""\u1{0:\u2}""""""; + Console.WriteLine(e); + } +}"; + CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics(); + } + + [Fact, WorkItem(1098612, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1098612")] + public void MissingConversionFromFormattableStringToIFormattable() + { + var text = +@"namespace System.Runtime.CompilerServices +{ + public static class FormattableStringFactory + { + public static FormattableString Create(string format, params object[] arguments) + { + return null; + } + } +} + +namespace System +{ + public abstract class FormattableString + { + } +} + +static class C +{ + static void Main() + { + System.IFormattable i = $""""""{""""}""""""; + } +}"; + CreateCompilationWithMscorlib40AndSystemCore(text).VerifyEmitDiagnostics( + // (23,33): error CS0029: Cannot implicitly convert type 'FormattableString' to 'IFormattable' + // System.IFormattable i = $"""{""}"""; + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""""""{""""}""""""").WithArguments("System.FormattableString", "System.IFormattable").WithLocation(23, 33)); + } + + [Fact] + public void InterpolatedStringBeforeCSharp6() + { + var text = @" +class C +{ + string M() + { + return $""""""hello""""""; + } +}"; + + CreateCompilation(text, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5)).VerifyDiagnostics( + // (6,16): error CS8026: Feature 'interpolated strings' is not available in C# 5. Please use language version 6 or greater. + // return $"""hello"""; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, @"$""""""hello""""""").WithArguments("interpolated strings", "6").WithLocation(6, 16)); + } + + [Fact] + public void InterpolatedStringWithReplacementBeforeCSharp6() + { + var text = @" +class C +{ + string M() + { + string other = """"""world""""""; + return $""""""hello + {other}""""""; + } +}"; + + + 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. + // string other = """world"""; + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""world""""""").WithArguments("raw string literals").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 new file mode 100644 index 0000000000000..5d738b9255dc7 --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs @@ -0,0 +1,13472 @@ +// Licensed to the .NET Foundation under one or more 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.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics; + +public partial class RawInterpolationTests : CompilingTestBase +{ + [Theory, WorkItem(54702, "https://github.com/dotnet/roslyn/issues/54702")] + [InlineData(@"$""""""{s1}{s2}""""""", @"$""""""{s1}{s2}{s3}""""""", @"$""""""{s1}{s2}{s3}{s4}""""""", @"$""""""{s1}{s2}{s3}{s4}{s5}""""""")] + [InlineData(@"$""""""{s1}"""""" + $""""""{s2}""""""", @"$""""""{s1}"""""" + $""""""{s2}"""""" + $""""""{s3}""""""", @"$""""""{s1}"""""" + $""""""{s2}"""""" + $""""""{s3}"""""" + $""""""{s4}""""""", @"$""""""{s1}"""""" + $""""""{s2}"""""" + $""""""{s3}"""""" + $""""""{s4}"""""" + $""""""{s5}""""""")] + public void InterpolatedStringHandler_ConcatPreferencesForAllStringElements(string twoComponents, string threeComponents, string fourComponents, string fiveComponents) + { + var code = @" +using System; +Console.WriteLine(TwoComponents()); +Console.WriteLine(ThreeComponents()); +Console.WriteLine(FourComponents()); +Console.WriteLine(FiveComponents()); + +string TwoComponents() +{ + string s1 = ""1""; + string s2 = ""2""; + return " + twoComponents + @"; +} + +string ThreeComponents() +{ + string s1 = ""1""; + string s2 = ""2""; + string s3 = ""3""; + return " + threeComponents + @"; +} + +string FourComponents() +{ + string s1 = ""1""; + string s2 = ""2""; + string s3 = ""3""; + string s4 = ""4""; + return " + fourComponents + @"; +} + +string FiveComponents() +{ + string s1 = ""1""; + string s2 = ""2""; + string s3 = ""3""; + string s4 = ""4""; + string s5 = ""5""; + return " + fiveComponents + @"; +} +"; + + var handler = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerify(new[] { code, handler }, expectedOutput: @" +12 +123 +1234 +value:1 +value:2 +value:3 +value:4 +value:5 +"); + + verifier.VerifyIL("Program.<
$>g__TwoComponents|0_0()", @" +{ + // Code size 18 (0x12) + .maxstack 2 + .locals init (string V_0) //s2 + IL_0000: ldstr ""1"" + IL_0005: ldstr ""2"" + IL_000a: stloc.0 + IL_000b: ldloc.0 + IL_000c: call ""string string.Concat(string, string)"" + IL_0011: ret +} +"); + + verifier.VerifyIL("Program.<
$>g__ThreeComponents|0_1()", @" +{ + // Code size 25 (0x19) + .maxstack 3 + .locals init (string V_0, //s2 + string V_1) //s3 + IL_0000: ldstr ""1"" + IL_0005: ldstr ""2"" + IL_000a: stloc.0 + IL_000b: ldstr ""3"" + IL_0010: stloc.1 + IL_0011: ldloc.0 + IL_0012: ldloc.1 + IL_0013: call ""string string.Concat(string, string, string)"" + IL_0018: ret +} +"); + + verifier.VerifyIL("Program.<
$>g__FourComponents|0_2()", @" +{ + // Code size 32 (0x20) + .maxstack 4 + .locals init (string V_0, //s2 + string V_1, //s3 + string V_2) //s4 + IL_0000: ldstr ""1"" + IL_0005: ldstr ""2"" + IL_000a: stloc.0 + IL_000b: ldstr ""3"" + IL_0010: stloc.1 + IL_0011: ldstr ""4"" + IL_0016: stloc.2 + IL_0017: ldloc.0 + IL_0018: ldloc.1 + IL_0019: ldloc.2 + IL_001a: call ""string string.Concat(string, string, string, string)"" + IL_001f: ret +} +"); + + verifier.VerifyIL("Program.<
$>g__FiveComponents|0_3()", @" +{ + // Code size 89 (0x59) + .maxstack 3 + .locals init (string V_0, //s1 + string V_1, //s2 + string V_2, //s3 + string V_3, //s4 + string V_4, //s5 + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5) + IL_0000: ldstr ""1"" + IL_0005: stloc.0 + IL_0006: ldstr ""2"" + IL_000b: stloc.1 + IL_000c: ldstr ""3"" + IL_0011: stloc.2 + IL_0012: ldstr ""4"" + IL_0017: stloc.3 + IL_0018: ldstr ""5"" + IL_001d: stloc.s V_4 + IL_001f: ldloca.s V_5 + IL_0021: ldc.i4.0 + IL_0022: ldc.i4.5 + IL_0023: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0028: ldloca.s V_5 + IL_002a: ldloc.0 + IL_002b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"" + IL_0030: ldloca.s V_5 + IL_0032: ldloc.1 + IL_0033: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"" + IL_0038: ldloca.s V_5 + IL_003a: ldloc.2 + IL_003b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"" + IL_0040: ldloca.s V_5 + IL_0042: ldloc.3 + IL_0043: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"" + IL_0048: ldloca.s V_5 + IL_004a: ldloc.s V_4 + IL_004c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"" + IL_0051: ldloca.s V_5 + IL_0053: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0058: ret +} +"); + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandler_OverloadsAndBoolReturns( + bool useDefaultParameters, + bool useBoolReturns, + bool constructorBoolArg, + [CombinatorialValues(@"$""""""base{a}{a,1}{a:X}{a,2:Y}""""""", @"$""""""base"""""" + $""""""{a}"""""" + $""""""{a,1}"""""" + $""""""{a:X}"""""" + $""""""{a,2:Y}""""""")] string expression) + { + var source = +@"int a = 1; +System.Console.WriteLine(" + expression + @");"; + + string interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters, useBoolReturns, constructorBoolArg: constructorBoolArg); + + string expectedOutput = useDefaultParameters ? +@"base +value:1,alignment:0:format: +value:1,alignment:1:format: +value:1,alignment:0:format:X +value:1,alignment:2:format:Y" : +@"base +value:1 +value:1,alignment:1 +value:1:format:X +value:1,alignment:2:format:Y"; + + string expectedIl = getIl(); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: expectedOutput); + verifier.VerifyIL("", expectedIl); + + var comp1 = CreateCompilation(interpolatedStringBuilder); + + foreach (var reference in new[] { comp1.EmitToImageReference(), comp1.ToMetadataReference() }) + { + var comp2 = CreateCompilation(source, new[] { reference }); + verifier = CompileAndVerify(comp2, expectedOutput: expectedOutput); + verifier.VerifyIL("", expectedIl); + } + + string getIl() => (useDefaultParameters, useBoolReturns, constructorBoolArg) switch + { + (useDefaultParameters: false, useBoolReturns: false, constructorBoolArg: false) => @" +{ + // Code size 80 (0x50) + .maxstack 4 + .locals init (int V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.4 + IL_0005: ldc.i4.4 + IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_000b: ldloca.s V_1 + IL_000d: ldstr ""base"" + IL_0012: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0017: ldloca.s V_1 + IL_0019: ldloc.0 + IL_001a: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_001f: ldloca.s V_1 + IL_0021: ldloc.0 + IL_0022: ldc.i4.1 + IL_0023: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int)"" + IL_0028: ldloca.s V_1 + IL_002a: ldloc.0 + IL_002b: ldstr ""X"" + IL_0030: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, string)"" + IL_0035: ldloca.s V_1 + IL_0037: ldloc.0 + IL_0038: ldc.i4.2 + IL_0039: ldstr ""Y"" + IL_003e: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0043: ldloca.s V_1 + IL_0045: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_004a: call ""void System.Console.WriteLine(string)"" + IL_004f: ret +} +", + (useDefaultParameters: true, useBoolReturns: false, constructorBoolArg: false) => @" +{ + // Code size 84 (0x54) + .maxstack 4 + .locals init (int V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.4 + IL_0005: ldc.i4.4 + IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_000b: ldloca.s V_1 + IL_000d: ldstr ""base"" + IL_0012: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0017: ldloca.s V_1 + IL_0019: ldloc.0 + IL_001a: ldc.i4.0 + IL_001b: ldnull + IL_001c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0021: ldloca.s V_1 + IL_0023: ldloc.0 + IL_0024: ldc.i4.1 + IL_0025: ldnull + IL_0026: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_002b: ldloca.s V_1 + IL_002d: ldloc.0 + IL_002e: ldc.i4.0 + IL_002f: ldstr ""X"" + IL_0034: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0039: ldloca.s V_1 + IL_003b: ldloc.0 + IL_003c: ldc.i4.2 + IL_003d: ldstr ""Y"" + IL_0042: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0047: ldloca.s V_1 + IL_0049: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_004e: call ""void System.Console.WriteLine(string)"" + IL_0053: ret +} +", + (useDefaultParameters: false, useBoolReturns: true, constructorBoolArg: false) => @" +{ + // Code size 92 (0x5c) + .maxstack 4 + .locals init (int V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.4 + IL_0005: ldc.i4.4 + IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_000b: ldloca.s V_1 + IL_000d: ldstr ""base"" + IL_0012: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0017: brfalse.s IL_004d + IL_0019: ldloca.s V_1 + IL_001b: ldloc.0 + IL_001c: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0021: brfalse.s IL_004d + IL_0023: ldloca.s V_1 + IL_0025: ldloc.0 + IL_0026: ldc.i4.1 + IL_0027: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int)"" + IL_002c: brfalse.s IL_004d + IL_002e: ldloca.s V_1 + IL_0030: ldloc.0 + IL_0031: ldstr ""X"" + IL_0036: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, string)"" + IL_003b: brfalse.s IL_004d + IL_003d: ldloca.s V_1 + IL_003f: ldloc.0 + IL_0040: ldc.i4.2 + IL_0041: ldstr ""Y"" + IL_0046: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_004b: br.s IL_004e + IL_004d: ldc.i4.0 + IL_004e: pop + IL_004f: ldloca.s V_1 + IL_0051: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0056: call ""void System.Console.WriteLine(string)"" + IL_005b: ret +} +", + (useDefaultParameters: true, useBoolReturns: true, constructorBoolArg: false) => @" +{ + // Code size 96 (0x60) + .maxstack 4 + .locals init (int V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.4 + IL_0005: ldc.i4.4 + IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_000b: ldloca.s V_1 + IL_000d: ldstr ""base"" + IL_0012: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0017: brfalse.s IL_0051 + IL_0019: ldloca.s V_1 + IL_001b: ldloc.0 + IL_001c: ldc.i4.0 + IL_001d: ldnull + IL_001e: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0023: brfalse.s IL_0051 + IL_0025: ldloca.s V_1 + IL_0027: ldloc.0 + IL_0028: ldc.i4.1 + IL_0029: ldnull + IL_002a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_002f: brfalse.s IL_0051 + IL_0031: ldloca.s V_1 + IL_0033: ldloc.0 + IL_0034: ldc.i4.0 + IL_0035: ldstr ""X"" + IL_003a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_003f: brfalse.s IL_0051 + IL_0041: ldloca.s V_1 + IL_0043: ldloc.0 + IL_0044: ldc.i4.2 + IL_0045: ldstr ""Y"" + IL_004a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_004f: br.s IL_0052 + IL_0051: ldc.i4.0 + IL_0052: pop + IL_0053: ldloca.s V_1 + IL_0055: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_005a: call ""void System.Console.WriteLine(string)"" + IL_005f: ret +} +", + (useDefaultParameters: false, useBoolReturns: false, constructorBoolArg: true) => @" +{ + // Code size 84 (0x54) + .maxstack 4 + .locals init (int V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1, + bool V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldc.i4.4 + IL_0003: ldc.i4.4 + IL_0004: ldloca.s V_2 + IL_0006: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)"" + IL_000b: stloc.1 + IL_000c: ldloc.2 + IL_000d: brfalse.s IL_0047 + IL_000f: ldloca.s V_1 + IL_0011: ldstr ""base"" + IL_0016: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_001b: ldloca.s V_1 + IL_001d: ldloc.0 + IL_001e: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0023: ldloca.s V_1 + IL_0025: ldloc.0 + IL_0026: ldc.i4.1 + IL_0027: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int)"" + IL_002c: ldloca.s V_1 + IL_002e: ldloc.0 + IL_002f: ldstr ""X"" + IL_0034: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, string)"" + IL_0039: ldloca.s V_1 + IL_003b: ldloc.0 + IL_003c: ldc.i4.2 + IL_003d: ldstr ""Y"" + IL_0042: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0047: ldloca.s V_1 + IL_0049: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_004e: call ""void System.Console.WriteLine(string)"" + IL_0053: ret +} +", + (useDefaultParameters: true, useBoolReturns: false, constructorBoolArg: true) => @" +{ + // Code size 88 (0x58) + .maxstack 4 + .locals init (int V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1, + bool V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldc.i4.4 + IL_0003: ldc.i4.4 + IL_0004: ldloca.s V_2 + IL_0006: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)"" + IL_000b: stloc.1 + IL_000c: ldloc.2 + IL_000d: brfalse.s IL_004b + IL_000f: ldloca.s V_1 + IL_0011: ldstr ""base"" + IL_0016: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_001b: ldloca.s V_1 + IL_001d: ldloc.0 + IL_001e: ldc.i4.0 + IL_001f: ldnull + IL_0020: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0025: ldloca.s V_1 + IL_0027: ldloc.0 + IL_0028: ldc.i4.1 + IL_0029: ldnull + IL_002a: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_002f: ldloca.s V_1 + IL_0031: ldloc.0 + IL_0032: ldc.i4.0 + IL_0033: ldstr ""X"" + IL_0038: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_003d: ldloca.s V_1 + IL_003f: ldloc.0 + IL_0040: ldc.i4.2 + IL_0041: ldstr ""Y"" + IL_0046: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_004b: ldloca.s V_1 + IL_004d: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0052: call ""void System.Console.WriteLine(string)"" + IL_0057: ret +} +", + (useDefaultParameters: false, useBoolReturns: true, constructorBoolArg: true) => @" +{ + // Code size 96 (0x60) + .maxstack 4 + .locals init (int V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1, + bool V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldc.i4.4 + IL_0003: ldc.i4.4 + IL_0004: ldloca.s V_2 + IL_0006: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)"" + IL_000b: stloc.1 + IL_000c: ldloc.2 + IL_000d: brfalse.s IL_0051 + IL_000f: ldloca.s V_1 + IL_0011: ldstr ""base"" + IL_0016: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_001b: brfalse.s IL_0051 + IL_001d: ldloca.s V_1 + IL_001f: ldloc.0 + IL_0020: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0025: brfalse.s IL_0051 + IL_0027: ldloca.s V_1 + IL_0029: ldloc.0 + IL_002a: ldc.i4.1 + IL_002b: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int)"" + IL_0030: brfalse.s IL_0051 + IL_0032: ldloca.s V_1 + IL_0034: ldloc.0 + IL_0035: ldstr ""X"" + IL_003a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, string)"" + IL_003f: brfalse.s IL_0051 + IL_0041: ldloca.s V_1 + IL_0043: ldloc.0 + IL_0044: ldc.i4.2 + IL_0045: ldstr ""Y"" + IL_004a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_004f: br.s IL_0052 + IL_0051: ldc.i4.0 + IL_0052: pop + IL_0053: ldloca.s V_1 + IL_0055: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_005a: call ""void System.Console.WriteLine(string)"" + IL_005f: ret +} +", + (useDefaultParameters: true, useBoolReturns: true, constructorBoolArg: true) => @" +{ + // Code size 100 (0x64) + .maxstack 4 + .locals init (int V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1, + bool V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldc.i4.4 + IL_0003: ldc.i4.4 + IL_0004: ldloca.s V_2 + IL_0006: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)"" + IL_000b: stloc.1 + IL_000c: ldloc.2 + IL_000d: brfalse.s IL_0055 + IL_000f: ldloca.s V_1 + IL_0011: ldstr ""base"" + IL_0016: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_001b: brfalse.s IL_0055 + IL_001d: ldloca.s V_1 + IL_001f: ldloc.0 + IL_0020: ldc.i4.0 + IL_0021: ldnull + IL_0022: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0027: brfalse.s IL_0055 + IL_0029: ldloca.s V_1 + IL_002b: ldloc.0 + IL_002c: ldc.i4.1 + IL_002d: ldnull + IL_002e: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0033: brfalse.s IL_0055 + IL_0035: ldloca.s V_1 + IL_0037: ldloc.0 + IL_0038: ldc.i4.0 + IL_0039: ldstr ""X"" + IL_003e: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0043: brfalse.s IL_0055 + IL_0045: ldloca.s V_1 + IL_0047: ldloc.0 + IL_0048: ldc.i4.2 + IL_0049: ldstr ""Y"" + IL_004e: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int, int, string)"" + IL_0053: br.s IL_0056 + IL_0055: ldc.i4.0 + IL_0056: pop + IL_0057: ldloca.s V_1 + IL_0059: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_005e: call ""void System.Console.WriteLine(string)"" + IL_0063: ret +} +", + }; + } + + [Fact] + public void UseOfSpanInInterpolationHole_CSharp9() + { + var source = @" +using System; +ReadOnlySpan span = stackalloc char[1]; +Console.WriteLine($""""""{span}"""""");"; + + 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. + // Console.WriteLine($"""{span}"""); + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{span}""""""").WithArguments("raw string literals").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)); + } + + [ConditionalTheory(typeof(MonoOrCoreClrOnly))] + [CombinatorialData] + public void UseOfSpanInInterpolationHole(bool useDefaultParameters, bool useBoolReturns, bool constructorBoolArg, + [CombinatorialValues(@"$""""""base{a}{a,1}{a:X}{a,2:Y}""""""", @"$""""""base"""""" + $""""""{a}"""""" + $""""""{a,1}"""""" + $""""""{a:X}"""""" + $""""""{a,2:Y}""""""")] string expression) + { + var source = +@" +using System; +ReadOnlySpan a = ""1""; +System.Console.WriteLine(" + expression + ");"; + + string interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters, useBoolReturns, constructorBoolArg: constructorBoolArg); + + string expectedOutput = useDefaultParameters ? +@"base +value:1,alignment:0:format: +value:1,alignment:1:format: +value:1,alignment:0:format:X +value:1,alignment:2:format:Y" : +@"base +value:1 +value:1,alignment:1 +value:1:format:X +value:1,alignment:2:format:Y"; + + string expectedIl = getIl(); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: expectedOutput, targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.RegularPreview); + verifier.VerifyIL("", expectedIl); + + var comp1 = CreateCompilation(interpolatedStringBuilder, targetFramework: TargetFramework.NetCoreApp); + + foreach (var reference in new[] { comp1.EmitToImageReference(), comp1.ToMetadataReference() }) + { + var comp2 = CreateCompilation(source, new[] { reference }, targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.RegularPreview); + verifier = CompileAndVerify(comp2, expectedOutput: expectedOutput); + verifier.VerifyIL("", expectedIl); + } + + string getIl() => (useDefaultParameters, useBoolReturns, constructorBoolArg) switch + { + (useDefaultParameters: false, useBoolReturns: false, constructorBoolArg: false) => @" +{ + // Code size 89 (0x59) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldstr ""1"" + IL_0005: call ""System.ReadOnlySpan string.op_Implicit(string)"" + IL_000a: stloc.0 + IL_000b: ldloca.s V_1 + IL_000d: ldc.i4.4 + IL_000e: ldc.i4.4 + IL_000f: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0014: ldloca.s V_1 + IL_0016: ldstr ""base"" + IL_001b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0020: ldloca.s V_1 + IL_0022: ldloc.0 + IL_0023: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan)"" + IL_0028: ldloca.s V_1 + IL_002a: ldloc.0 + IL_002b: ldc.i4.1 + IL_002c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int)"" + IL_0031: ldloca.s V_1 + IL_0033: ldloc.0 + IL_0034: ldstr ""X"" + IL_0039: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, string)"" + IL_003e: ldloca.s V_1 + IL_0040: ldloc.0 + IL_0041: ldc.i4.2 + IL_0042: ldstr ""Y"" + IL_0047: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_004c: ldloca.s V_1 + IL_004e: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0053: call ""void System.Console.WriteLine(string)"" + IL_0058: ret +} +", + (useDefaultParameters: true, useBoolReturns: false, constructorBoolArg: false) => @" +{ + // Code size 93 (0x5d) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldstr ""1"" + IL_0005: call ""System.ReadOnlySpan string.op_Implicit(string)"" + IL_000a: stloc.0 + IL_000b: ldloca.s V_1 + IL_000d: ldc.i4.4 + IL_000e: ldc.i4.4 + IL_000f: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0014: ldloca.s V_1 + IL_0016: ldstr ""base"" + IL_001b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0020: ldloca.s V_1 + IL_0022: ldloc.0 + IL_0023: ldc.i4.0 + IL_0024: ldnull + IL_0025: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_002a: ldloca.s V_1 + IL_002c: ldloc.0 + IL_002d: ldc.i4.1 + IL_002e: ldnull + IL_002f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0034: ldloca.s V_1 + IL_0036: ldloc.0 + IL_0037: ldc.i4.0 + IL_0038: ldstr ""X"" + IL_003d: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0042: ldloca.s V_1 + IL_0044: ldloc.0 + IL_0045: ldc.i4.2 + IL_0046: ldstr ""Y"" + IL_004b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0050: ldloca.s V_1 + IL_0052: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0057: call ""void System.Console.WriteLine(string)"" + IL_005c: ret +} +", + (useDefaultParameters: false, useBoolReturns: true, constructorBoolArg: false) => @" +{ + // Code size 101 (0x65) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldstr ""1"" + IL_0005: call ""System.ReadOnlySpan string.op_Implicit(string)"" + IL_000a: stloc.0 + IL_000b: ldloca.s V_1 + IL_000d: ldc.i4.4 + IL_000e: ldc.i4.4 + IL_000f: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0014: ldloca.s V_1 + IL_0016: ldstr ""base"" + IL_001b: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0020: brfalse.s IL_0056 + IL_0022: ldloca.s V_1 + IL_0024: ldloc.0 + IL_0025: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan)"" + IL_002a: brfalse.s IL_0056 + IL_002c: ldloca.s V_1 + IL_002e: ldloc.0 + IL_002f: ldc.i4.1 + IL_0030: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int)"" + IL_0035: brfalse.s IL_0056 + IL_0037: ldloca.s V_1 + IL_0039: ldloc.0 + IL_003a: ldstr ""X"" + IL_003f: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, string)"" + IL_0044: brfalse.s IL_0056 + IL_0046: ldloca.s V_1 + IL_0048: ldloc.0 + IL_0049: ldc.i4.2 + IL_004a: ldstr ""Y"" + IL_004f: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0054: br.s IL_0057 + IL_0056: ldc.i4.0 + IL_0057: pop + IL_0058: ldloca.s V_1 + IL_005a: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_005f: call ""void System.Console.WriteLine(string)"" + IL_0064: ret +} +", + (useDefaultParameters: true, useBoolReturns: true, constructorBoolArg: false) => @" +{ + // Code size 105 (0x69) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldstr ""1"" + IL_0005: call ""System.ReadOnlySpan string.op_Implicit(string)"" + IL_000a: stloc.0 + IL_000b: ldloca.s V_1 + IL_000d: ldc.i4.4 + IL_000e: ldc.i4.4 + IL_000f: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0014: ldloca.s V_1 + IL_0016: ldstr ""base"" + IL_001b: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0020: brfalse.s IL_005a + IL_0022: ldloca.s V_1 + IL_0024: ldloc.0 + IL_0025: ldc.i4.0 + IL_0026: ldnull + IL_0027: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_002c: brfalse.s IL_005a + IL_002e: ldloca.s V_1 + IL_0030: ldloc.0 + IL_0031: ldc.i4.1 + IL_0032: ldnull + IL_0033: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0038: brfalse.s IL_005a + IL_003a: ldloca.s V_1 + IL_003c: ldloc.0 + IL_003d: ldc.i4.0 + IL_003e: ldstr ""X"" + IL_0043: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0048: brfalse.s IL_005a + IL_004a: ldloca.s V_1 + IL_004c: ldloc.0 + IL_004d: ldc.i4.2 + IL_004e: ldstr ""Y"" + IL_0053: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0058: br.s IL_005b + IL_005a: ldc.i4.0 + IL_005b: pop + IL_005c: ldloca.s V_1 + IL_005e: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0063: call ""void System.Console.WriteLine(string)"" + IL_0068: ret +} +", + (useDefaultParameters: false, useBoolReturns: false, constructorBoolArg: true) => @" +{ + // Code size 93 (0x5d) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1, + bool V_2) + IL_0000: ldstr ""1"" + IL_0005: call ""System.ReadOnlySpan string.op_Implicit(string)"" + IL_000a: stloc.0 + IL_000b: ldc.i4.4 + IL_000c: ldc.i4.4 + IL_000d: ldloca.s V_2 + IL_000f: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)"" + IL_0014: stloc.1 + IL_0015: ldloc.2 + IL_0016: brfalse.s IL_0050 + IL_0018: ldloca.s V_1 + IL_001a: ldstr ""base"" + IL_001f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0024: ldloca.s V_1 + IL_0026: ldloc.0 + IL_0027: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan)"" + IL_002c: ldloca.s V_1 + IL_002e: ldloc.0 + IL_002f: ldc.i4.1 + IL_0030: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int)"" + IL_0035: ldloca.s V_1 + IL_0037: ldloc.0 + IL_0038: ldstr ""X"" + IL_003d: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, string)"" + IL_0042: ldloca.s V_1 + IL_0044: ldloc.0 + IL_0045: ldc.i4.2 + IL_0046: ldstr ""Y"" + IL_004b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0050: ldloca.s V_1 + IL_0052: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0057: call ""void System.Console.WriteLine(string)"" + IL_005c: ret +} +", + (useDefaultParameters: false, useBoolReturns: true, constructorBoolArg: true) => @" +{ + // Code size 105 (0x69) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1, + bool V_2) + IL_0000: ldstr ""1"" + IL_0005: call ""System.ReadOnlySpan string.op_Implicit(string)"" + IL_000a: stloc.0 + IL_000b: ldc.i4.4 + IL_000c: ldc.i4.4 + IL_000d: ldloca.s V_2 + IL_000f: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)"" + IL_0014: stloc.1 + IL_0015: ldloc.2 + IL_0016: brfalse.s IL_005a + IL_0018: ldloca.s V_1 + IL_001a: ldstr ""base"" + IL_001f: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0024: brfalse.s IL_005a + IL_0026: ldloca.s V_1 + IL_0028: ldloc.0 + IL_0029: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan)"" + IL_002e: brfalse.s IL_005a + IL_0030: ldloca.s V_1 + IL_0032: ldloc.0 + IL_0033: ldc.i4.1 + IL_0034: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int)"" + IL_0039: brfalse.s IL_005a + IL_003b: ldloca.s V_1 + IL_003d: ldloc.0 + IL_003e: ldstr ""X"" + IL_0043: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, string)"" + IL_0048: brfalse.s IL_005a + IL_004a: ldloca.s V_1 + IL_004c: ldloc.0 + IL_004d: ldc.i4.2 + IL_004e: ldstr ""Y"" + IL_0053: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0058: br.s IL_005b + IL_005a: ldc.i4.0 + IL_005b: pop + IL_005c: ldloca.s V_1 + IL_005e: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0063: call ""void System.Console.WriteLine(string)"" + IL_0068: ret +} +", + (useDefaultParameters: true, useBoolReturns: false, constructorBoolArg: true) => @" +{ + // Code size 97 (0x61) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1, + bool V_2) + IL_0000: ldstr ""1"" + IL_0005: call ""System.ReadOnlySpan string.op_Implicit(string)"" + IL_000a: stloc.0 + IL_000b: ldc.i4.4 + IL_000c: ldc.i4.4 + IL_000d: ldloca.s V_2 + IL_000f: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)"" + IL_0014: stloc.1 + IL_0015: ldloc.2 + IL_0016: brfalse.s IL_0054 + IL_0018: ldloca.s V_1 + IL_001a: ldstr ""base"" + IL_001f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0024: ldloca.s V_1 + IL_0026: ldloc.0 + IL_0027: ldc.i4.0 + IL_0028: ldnull + IL_0029: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_002e: ldloca.s V_1 + IL_0030: ldloc.0 + IL_0031: ldc.i4.1 + IL_0032: ldnull + IL_0033: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0038: ldloca.s V_1 + IL_003a: ldloc.0 + IL_003b: ldc.i4.0 + IL_003c: ldstr ""X"" + IL_0041: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0046: ldloca.s V_1 + IL_0048: ldloc.0 + IL_0049: ldc.i4.2 + IL_004a: ldstr ""Y"" + IL_004f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0054: ldloca.s V_1 + IL_0056: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_005b: call ""void System.Console.WriteLine(string)"" + IL_0060: ret +} +", + (useDefaultParameters: true, useBoolReturns: true, constructorBoolArg: true) => @" +{ + // Code size 109 (0x6d) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //a + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1, + bool V_2) + IL_0000: ldstr ""1"" + IL_0005: call ""System.ReadOnlySpan string.op_Implicit(string)"" + IL_000a: stloc.0 + IL_000b: ldc.i4.4 + IL_000c: ldc.i4.4 + IL_000d: ldloca.s V_2 + IL_000f: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)"" + IL_0014: stloc.1 + IL_0015: ldloc.2 + IL_0016: brfalse.s IL_005e + IL_0018: ldloca.s V_1 + IL_001a: ldstr ""base"" + IL_001f: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0024: brfalse.s IL_005e + IL_0026: ldloca.s V_1 + IL_0028: ldloc.0 + IL_0029: ldc.i4.0 + IL_002a: ldnull + IL_002b: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_0030: brfalse.s IL_005e + IL_0032: ldloca.s V_1 + IL_0034: ldloc.0 + IL_0035: ldc.i4.1 + IL_0036: ldnull + IL_0037: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_003c: brfalse.s IL_005e + IL_003e: ldloca.s V_1 + IL_0040: ldloc.0 + IL_0041: ldc.i4.0 + IL_0042: ldstr ""X"" + IL_0047: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_004c: brfalse.s IL_005e + IL_004e: ldloca.s V_1 + IL_0050: ldloc.0 + IL_0051: ldc.i4.2 + IL_0052: ldstr ""Y"" + IL_0057: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan, int, string)"" + IL_005c: br.s IL_005f + IL_005e: ldc.i4.0 + IL_005f: pop + IL_0060: ldloca.s V_1 + IL_0062: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0067: call ""void System.Console.WriteLine(string)"" + IL_006c: ret +} +", + }; + } + + [Theory] + [InlineData(@"$""""""base{Throw()}{a = 2}""""""")] + [InlineData(@"$""""""base"""""" + $""""""{Throw()}"""""" + $""""""{a = 2}""""""")] + public void BoolReturns_ShortCircuit(string expression) + { + var source = @" +using System; +int a = 1; +Console.Write(" + expression + @"); +Console.WriteLine(a); +string Throw() => throw new Exception();"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: true, returnExpression: "false"); + + CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @" +base +1"); + } + + [Theory] + [CombinatorialData] + public void BoolOutParameter_ShortCircuits(bool useBoolReturns, + [CombinatorialValues(@"$""""""{Throw()}{a = 2}""""""", @"$""""""{Throw()}"""""" + $""""""{a = 2}""""""")] string expression) + { + var source = @" +using System; +int a = 1; +Console.WriteLine(a); +Console.WriteLine(" + expression + @"); +Console.WriteLine(a); +string Throw() => throw new Exception(); +"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: useBoolReturns, constructorBoolArg: true, constructorSuccessResult: false); + + CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @" +1 + +1"); + } + + [Theory] + [InlineData(@"$""""""base{await Hole()}""""""")] + [InlineData(@"$""""""base"""""" + $""""""{await Hole()}""""""")] + public void AwaitInHoles_UsesFormat(string expression) + { + var source = @" +using System; +using System.Threading.Tasks; + +Console.WriteLine(" + expression + @"); +Task Hole() => Task.FromResult(1);"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"base1"); + + verifier.VerifyIL("Program.<
$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", !expression.Contains("+") ? @" +{ + // Code size 164 (0xa4) + .maxstack 3 + .locals init (int V_0, + int V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.<
$>d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_003e + IL_000a: call ""System.Threading.Tasks.Task Program.<
$>g__Hole|0_0()"" + IL_000f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0014: stloc.2 + IL_0015: ldloca.s V_2 + IL_0017: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_001c: brtrue.s IL_005a + IL_001e: ldarg.0 + IL_001f: ldc.i4.0 + IL_0020: dup + IL_0021: stloc.0 + IL_0022: stfld ""int Program.<
$>d__0.<>1__state"" + IL_0027: ldarg.0 + IL_0028: ldloc.2 + IL_0029: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_002e: ldarg.0 + IL_002f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_0034: ldloca.s V_2 + IL_0036: ldarg.0 + IL_0037: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)"" + IL_003c: leave.s IL_00a3 + IL_003e: ldarg.0 + IL_003f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_0044: stloc.2 + IL_0045: ldarg.0 + IL_0046: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_004b: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0051: ldarg.0 + IL_0052: ldc.i4.m1 + IL_0053: dup + IL_0054: stloc.0 + IL_0055: stfld ""int Program.<
$>d__0.<>1__state"" + IL_005a: ldloca.s V_2 + IL_005c: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0061: stloc.1 + IL_0062: ldstr ""base{0}"" + IL_0067: ldloc.1 + IL_0068: box ""int"" + IL_006d: call ""string string.Format(string, object)"" + IL_0072: call ""void System.Console.WriteLine(string)"" + IL_0077: leave.s IL_0090 + } + catch System.Exception + { + IL_0079: stloc.3 + IL_007a: ldarg.0 + IL_007b: ldc.i4.s -2 + IL_007d: stfld ""int Program.<
$>d__0.<>1__state"" + IL_0082: ldarg.0 + IL_0083: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_0088: ldloc.3 + IL_0089: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_008e: leave.s IL_00a3 + } + IL_0090: ldarg.0 + IL_0091: ldc.i4.s -2 + IL_0093: stfld ""int Program.<
$>d__0.<>1__state"" + IL_0098: ldarg.0 + IL_0099: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_009e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00a3: ret +} +" +: @" +{ + // Code size 174 (0xae) + .maxstack 3 + .locals init (int V_0, + int V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.<
$>d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_003e + IL_000a: call ""System.Threading.Tasks.Task Program.<
$>g__Hole|0_0()"" + IL_000f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0014: stloc.2 + IL_0015: ldloca.s V_2 + IL_0017: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_001c: brtrue.s IL_005a + IL_001e: ldarg.0 + IL_001f: ldc.i4.0 + IL_0020: dup + IL_0021: stloc.0 + IL_0022: stfld ""int Program.<
$>d__0.<>1__state"" + IL_0027: ldarg.0 + IL_0028: ldloc.2 + IL_0029: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_002e: ldarg.0 + IL_002f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_0034: ldloca.s V_2 + IL_0036: ldarg.0 + IL_0037: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)"" + IL_003c: leave.s IL_00ad + IL_003e: ldarg.0 + IL_003f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_0044: stloc.2 + IL_0045: ldarg.0 + IL_0046: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_004b: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0051: ldarg.0 + IL_0052: ldc.i4.m1 + IL_0053: dup + IL_0054: stloc.0 + IL_0055: stfld ""int Program.<
$>d__0.<>1__state"" + IL_005a: ldloca.s V_2 + IL_005c: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0061: stloc.1 + IL_0062: ldstr ""base"" + IL_0067: ldstr ""{0}"" + IL_006c: ldloc.1 + IL_006d: box ""int"" + IL_0072: call ""string string.Format(string, object)"" + IL_0077: call ""string string.Concat(string, string)"" + IL_007c: call ""void System.Console.WriteLine(string)"" + IL_0081: leave.s IL_009a + } + catch System.Exception + { + IL_0083: stloc.3 + IL_0084: ldarg.0 + IL_0085: ldc.i4.s -2 + IL_0087: stfld ""int Program.<
$>d__0.<>1__state"" + IL_008c: ldarg.0 + IL_008d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_0092: ldloc.3 + IL_0093: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0098: leave.s IL_00ad + } + IL_009a: ldarg.0 + IL_009b: ldc.i4.s -2 + IL_009d: stfld ""int Program.<
$>d__0.<>1__state"" + IL_00a2: ldarg.0 + IL_00a3: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_00a8: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00ad: ret +}"); + } + + [Theory] + [InlineData(@"$""""""base{hole}""""""")] + [InlineData(@"$""""""base"""""" + $""""""{hole}""""""")] + public void NoAwaitInHoles_UsesBuilder(string expression) + { + var source = @" +using System; +using System.Threading.Tasks; + +var hole = await Hole(); +Console.WriteLine(" + expression + @"); +Task Hole() => Task.FromResult(1);"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @" +base +value:1"); + + verifier.VerifyIL("Program.<
$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" +{ + // Code size 185 (0xb9) + .maxstack 3 + .locals init (int V_0, + int V_1, //hole + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.<
$>d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_003e + IL_000a: call ""System.Threading.Tasks.Task Program.<
$>g__Hole|0_0()"" + IL_000f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0014: stloc.2 + IL_0015: ldloca.s V_2 + IL_0017: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_001c: brtrue.s IL_005a + IL_001e: ldarg.0 + IL_001f: ldc.i4.0 + IL_0020: dup + IL_0021: stloc.0 + IL_0022: stfld ""int Program.<
$>d__0.<>1__state"" + IL_0027: ldarg.0 + IL_0028: ldloc.2 + IL_0029: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_002e: ldarg.0 + IL_002f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_0034: ldloca.s V_2 + IL_0036: ldarg.0 + IL_0037: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)"" + IL_003c: leave.s IL_00b8 + IL_003e: ldarg.0 + IL_003f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_0044: stloc.2 + IL_0045: ldarg.0 + IL_0046: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_004b: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0051: ldarg.0 + IL_0052: ldc.i4.m1 + IL_0053: dup + IL_0054: stloc.0 + IL_0055: stfld ""int Program.<
$>d__0.<>1__state"" + IL_005a: ldloca.s V_2 + IL_005c: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0061: stloc.1 + IL_0062: ldc.i4.4 + IL_0063: ldc.i4.1 + IL_0064: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0069: stloc.3 + IL_006a: ldloca.s V_3 + IL_006c: ldstr ""base"" + IL_0071: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0076: ldloca.s V_3 + IL_0078: ldloc.1 + IL_0079: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_007e: ldloca.s V_3 + IL_0080: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0085: call ""void System.Console.WriteLine(string)"" + IL_008a: leave.s IL_00a5 + } + catch System.Exception + { + IL_008c: stloc.s V_4 + IL_008e: ldarg.0 + IL_008f: ldc.i4.s -2 + IL_0091: stfld ""int Program.<
$>d__0.<>1__state"" + IL_0096: ldarg.0 + IL_0097: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_009c: ldloc.s V_4 + IL_009e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_00a3: leave.s IL_00b8 + } + IL_00a5: ldarg.0 + IL_00a6: ldc.i4.s -2 + IL_00a8: stfld ""int Program.<
$>d__0.<>1__state"" + IL_00ad: ldarg.0 + IL_00ae: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_00b3: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00b8: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""base{hole}""""""")] + [InlineData(@"$""""""base"""""" + $""""""{hole}""""""")] + public void NoAwaitInHoles_AwaitInExpression_UsesBuilder(string expression) + { + var source = @" +using System; +using System.Threading.Tasks; + +var hole = 2; +Test(await M(1), " + expression + @", await M(3)); +void Test(int i1, string s, int i2) => Console.WriteLine(s); +Task M(int i) +{ + Console.WriteLine(i); + return Task.FromResult(1); +}"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @" +1 +3 +base +value:2"); + + verifier.VerifyIL("Program.<
$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" +{ + // Code size 328 (0x148) + .maxstack 3 + .locals init (int V_0, + int V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.<
$>d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0050 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq IL_00dc + IL_0011: ldarg.0 + IL_0012: ldc.i4.2 + IL_0013: stfld ""int Program.<
$>d__0.5__2"" + IL_0018: ldc.i4.1 + IL_0019: call ""System.Threading.Tasks.Task Program.<
$>g__M|0_1(int)"" + IL_001e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0023: stloc.2 + IL_0024: ldloca.s V_2 + IL_0026: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_002b: brtrue.s IL_006c + IL_002d: ldarg.0 + IL_002e: ldc.i4.0 + IL_002f: dup + IL_0030: stloc.0 + IL_0031: stfld ""int Program.<
$>d__0.<>1__state"" + IL_0036: ldarg.0 + IL_0037: ldloc.2 + IL_0038: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_003d: ldarg.0 + IL_003e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_0043: ldloca.s V_2 + IL_0045: ldarg.0 + IL_0046: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)"" + IL_004b: leave IL_0147 + IL_0050: ldarg.0 + IL_0051: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_0056: stloc.2 + IL_0057: ldarg.0 + IL_0058: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_005d: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0063: ldarg.0 + IL_0064: ldc.i4.m1 + IL_0065: dup + IL_0066: stloc.0 + IL_0067: stfld ""int Program.<
$>d__0.<>1__state"" + IL_006c: ldarg.0 + IL_006d: ldloca.s V_2 + IL_006f: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0074: stfld ""int Program.<
$>d__0.<>7__wrap2"" + IL_0079: ldarg.0 + IL_007a: ldc.i4.4 + IL_007b: ldc.i4.1 + IL_007c: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0081: stloc.3 + IL_0082: ldloca.s V_3 + IL_0084: ldstr ""base"" + IL_0089: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_008e: ldloca.s V_3 + IL_0090: ldarg.0 + IL_0091: ldfld ""int Program.<
$>d__0.5__2"" + IL_0096: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_009b: ldloca.s V_3 + IL_009d: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_00a2: stfld ""string Program.<
$>d__0.<>7__wrap3"" + IL_00a7: ldc.i4.3 + IL_00a8: call ""System.Threading.Tasks.Task Program.<
$>g__M|0_1(int)"" + IL_00ad: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_00b2: stloc.2 + IL_00b3: ldloca.s V_2 + IL_00b5: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00ba: brtrue.s IL_00f8 + IL_00bc: ldarg.0 + IL_00bd: ldc.i4.1 + IL_00be: dup + IL_00bf: stloc.0 + IL_00c0: stfld ""int Program.<
$>d__0.<>1__state"" + IL_00c5: ldarg.0 + IL_00c6: ldloc.2 + IL_00c7: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_00cc: ldarg.0 + IL_00cd: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_00d2: ldloca.s V_2 + IL_00d4: ldarg.0 + IL_00d5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)"" + IL_00da: leave.s IL_0147 + IL_00dc: ldarg.0 + IL_00dd: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_00e2: stloc.2 + IL_00e3: ldarg.0 + IL_00e4: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_00e9: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00ef: ldarg.0 + IL_00f0: ldc.i4.m1 + IL_00f1: dup + IL_00f2: stloc.0 + IL_00f3: stfld ""int Program.<
$>d__0.<>1__state"" + IL_00f8: ldloca.s V_2 + IL_00fa: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00ff: stloc.1 + IL_0100: ldarg.0 + IL_0101: ldfld ""int Program.<
$>d__0.<>7__wrap2"" + IL_0106: ldarg.0 + IL_0107: ldfld ""string Program.<
$>d__0.<>7__wrap3"" + IL_010c: ldloc.1 + IL_010d: call ""void Program.<
$>g__Test|0_0(int, string, int)"" + IL_0112: ldarg.0 + IL_0113: ldnull + IL_0114: stfld ""string Program.<
$>d__0.<>7__wrap3"" + IL_0119: leave.s IL_0134 + } + catch System.Exception + { + IL_011b: stloc.s V_4 + IL_011d: ldarg.0 + IL_011e: ldc.i4.s -2 + IL_0120: stfld ""int Program.<
$>d__0.<>1__state"" + IL_0125: ldarg.0 + IL_0126: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_012b: ldloc.s V_4 + IL_012d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0132: leave.s IL_0147 + } + IL_0134: ldarg.0 + IL_0135: ldc.i4.s -2 + IL_0137: stfld ""int Program.<
$>d__0.<>1__state"" + IL_013c: ldarg.0 + IL_013d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_0142: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_0147: ret +} +"); + } + + [Theory, WorkItem(55609, "https://github.com/dotnet/roslyn/issues/55609")] + [InlineData(@"$""""""base{hole}""""""")] + [InlineData(@"$""""""base"""""" + $""""""{hole}""""""")] + public void DynamicInHoles_UsesFormat(string expression) + { + var source = @" +using System; +using System.Threading.Tasks; + +dynamic hole = 1; +Console.WriteLine(" + expression + @"); +"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerifyWithCSharp(new[] { source, interpolatedStringBuilder }, expectedOutput: @"base1"); + + verifier.VerifyIL("", expression.Contains('+') +? @" +{ + // Code size 34 (0x22) + .maxstack 3 + .locals init (object V_0) //hole + IL_0000: ldc.i4.1 + IL_0001: box ""int"" + IL_0006: stloc.0 + IL_0007: ldstr ""base"" + IL_000c: ldstr ""{0}"" + IL_0011: ldloc.0 + IL_0012: call ""string string.Format(string, object)"" + IL_0017: call ""string string.Concat(string, string)"" + IL_001c: call ""void System.Console.WriteLine(string)"" + IL_0021: ret +} +" +: @" +{ + // Code size 24 (0x18) + .maxstack 2 + .locals init (object V_0) //hole + IL_0000: ldc.i4.1 + IL_0001: box ""int"" + IL_0006: stloc.0 + IL_0007: ldstr ""base{0}"" + IL_000c: ldloc.0 + IL_000d: call ""string string.Format(string, object)"" + IL_0012: call ""void System.Console.WriteLine(string)"" + IL_0017: ret +} +"); + } + + [Theory, WorkItem(55609, "https://github.com/dotnet/roslyn/issues/55609")] + [InlineData(@"$""""""{hole}base""""""")] + [InlineData(@"$""""""{hole}"""""" + $""""""base""""""")] + public void DynamicInHoles_UsesFormat2(string expression) + { + var source = @" +using System; +using System.Threading.Tasks; + +dynamic hole = 1; +Console.WriteLine(" + expression + @"); +"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerifyWithCSharp(new[] { source, interpolatedStringBuilder }, expectedOutput: @"1base"); + + verifier.VerifyIL("", expression.Contains('+') +? @" +{ + // Code size 34 (0x22) + .maxstack 2 + .locals init (object V_0) //hole + IL_0000: ldc.i4.1 + IL_0001: box ""int"" + IL_0006: stloc.0 + IL_0007: ldstr ""{0}"" + IL_000c: ldloc.0 + IL_000d: call ""string string.Format(string, object)"" + IL_0012: ldstr ""base"" + IL_0017: call ""string string.Concat(string, string)"" + IL_001c: call ""void System.Console.WriteLine(string)"" + IL_0021: ret +} +" +: @" +{ + // Code size 24 (0x18) + .maxstack 2 + .locals init (object V_0) //hole + IL_0000: ldc.i4.1 + IL_0001: box ""int"" + IL_0006: stloc.0 + IL_0007: ldstr ""{0}base"" + IL_000c: ldloc.0 + IL_000d: call ""string string.Format(string, object)"" + IL_0012: call ""void System.Console.WriteLine(string)"" + IL_0017: ret +} +"); + } + + [Fact] + public void ImplicitConversionsInConstructor() + { + var code = @" +using System.Runtime.CompilerServices; + +CustomHandler c = $"""""" + +""""""; + +[InterpolatedStringHandler] +struct CustomHandler +{ + public CustomHandler(object literalLength, object formattedCount) {} +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerAttribute }); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 19 (0x13) + .maxstack 2 + IL_0000: ldc.i4.0 + IL_0001: box ""int"" + IL_0006: ldc.i4.0 + IL_0007: box ""int"" + IL_000c: newobj ""CustomHandler..ctor(object, object)"" + IL_0011: pop + IL_0012: ret +} +"); + } + + [Fact] + public void MissingCreate_01() + { + var code = @"_ = $""""""{(object)1}"""""";"; + + var interpolatedStringBuilder = @" +namespace System.Runtime.CompilerServices +{ + public ref struct DefaultInterpolatedStringHandler + { + public override string ToString() => throw null; + public void Dispose() => throw null; + public void AppendLiteral(string value) => throw null; + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; + } +} +"; + + var comp = CreateCompilation(new[] { code, interpolatedStringBuilder }); + comp.VerifyDiagnostics( + // (1,5): error CS1729: 'DefaultInterpolatedStringHandler' does not contain a constructor that takes 2 arguments + // _ = $"{(object)1}"; + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""""{(object)1}""""""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "2").WithLocation(1, 5), + // (1,5): error CS1729: 'DefaultInterpolatedStringHandler' does not contain a constructor that takes 3 arguments + // _ = $"{(object)1}"; + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""""{(object)1}""""""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "3").WithLocation(1, 5)); + } + + [Fact] + public void MissingCreate_02() + { + var code = @"_ = $""""""{(object)1}"""""";"; + + var interpolatedStringBuilder = @" +namespace System.Runtime.CompilerServices +{ + public ref struct DefaultInterpolatedStringHandler + { + public DefaultInterpolatedStringHandler(int literalLength) => throw null; + public override string ToString() => throw null; + public void Dispose() => throw null; + public void AppendLiteral(string value) => throw null; + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; + } +} +"; + + var comp = CreateCompilation(new[] { code, interpolatedStringBuilder }); + comp.VerifyDiagnostics( + // (1,5): error CS1729: 'DefaultInterpolatedStringHandler' does not contain a constructor that takes 2 arguments + // _ = $"{(object)1}"; + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""""{(object)1}""""""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "2").WithLocation(1, 5), + // (1,5): error CS1729: 'DefaultInterpolatedStringHandler' does not contain a constructor that takes 3 arguments + // _ = $"{(object)1}"; + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""""{(object)1}""""""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "3").WithLocation(1, 5)); + } + + [Fact] + public void MissingCreate_03() + { + var code = @"_ = $""""""{(object)1}"""""";"; + + var interpolatedStringBuilder = @" +namespace System.Runtime.CompilerServices +{ + public ref struct DefaultInterpolatedStringHandler + { + public DefaultInterpolatedStringHandler(ref int literalLength, int formattedCount) => throw null; + public override string ToString() => throw null; + public void Dispose() => throw null; + public void AppendLiteral(string value) => throw null; + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; + } +} +"; + + var comp = CreateCompilation(new[] { code, interpolatedStringBuilder }); + comp.VerifyDiagnostics( + // (1,5): error CS1620: Argument 1 must be passed with the 'ref' keyword + // _ = $"{(object)1}"; + Diagnostic(ErrorCode.ERR_BadArgRef, @"$""""""{(object)1}""""""").WithArguments("1", "ref").WithLocation(1, 5)); + } + + [Theory] + [InlineData(null)] + [InlineData("public string ToStringAndClear(int literalLength) => throw null;")] + [InlineData("public void ToStringAndClear() => throw null;")] + [InlineData("public static string ToStringAndClear() => throw null;")] + public void MissingWellKnownMethod_ToStringAndClear(string toStringAndClearMethod) + { + var code = @"_ = $""""""{(object)1}"""""";"; + + var interpolatedStringBuilder = @" +namespace System.Runtime.CompilerServices +{ + public ref struct DefaultInterpolatedStringHandler + { + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) => throw null; + " + toStringAndClearMethod + @" + public override string ToString() => throw null; + public void AppendLiteral(string value) => throw null; + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; + } +} +"; + + var comp = CreateCompilation(new[] { code, interpolatedStringBuilder }); + comp.VerifyDiagnostics(); + comp.VerifyEmitDiagnostics( + // (1,5): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear' + // _ = $"{(object)1}"; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"$""""""{(object)1}""""""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "ToStringAndClear").WithLocation(1, 5)); + } + + [Fact] + public void ObsoleteCreateMethod() + { + var code = @"_ = $""""""{(object)1}"""""";"; + + var interpolatedStringBuilder = @" +namespace System.Runtime.CompilerServices +{ + public ref struct DefaultInterpolatedStringHandler + { + [System.Obsolete(""Constructor is obsolete"", error: true)] + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) => throw null; + public void Dispose() => throw null; + public override string ToString() => throw null; + public void AppendLiteral(string value) => throw null; + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; + } +} +"; + + var comp = CreateCompilation(new[] { code, interpolatedStringBuilder }); + comp.VerifyDiagnostics( + // (1,5): error CS0619: 'DefaultInterpolatedStringHandler.DefaultInterpolatedStringHandler(int, int)' is obsolete: 'Constructor is obsolete' + // _ = $"{(object)1}"; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, @"$""""""{(object)1}""""""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.DefaultInterpolatedStringHandler(int, int)", "Constructor is obsolete").WithLocation(1, 5)); + } + + [Fact] + public void ObsoleteAppendLiteralMethod() + { + var code = @"_ = $""""""base{(object)1}"""""";"; + + var interpolatedStringBuilder = @" +namespace System.Runtime.CompilerServices +{ + public ref struct DefaultInterpolatedStringHandler + { + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) => throw null; + public void Dispose() => throw null; + public override string ToString() => throw null; + [System.Obsolete(""AppendLiteral is obsolete"", error: true)] + public void AppendLiteral(string value) => throw null; + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; + } +} +"; + + var comp = CreateCompilation(new[] { code, interpolatedStringBuilder }); + comp.VerifyDiagnostics( + // (1,7): error CS0619: 'DefaultInterpolatedStringHandler.AppendLiteral(string)' is obsolete: 'AppendLiteral is obsolete' + // _ = $"base{(object)1}"; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "base").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)", "AppendLiteral is obsolete").WithLocation(1, 9)); + } + + [Fact] + public void ObsoleteAppendFormattedMethod() + { + var code = @"_ = $""""""base{(object)1}"""""";"; + + var interpolatedStringBuilder = @" +namespace System.Runtime.CompilerServices +{ + public ref struct DefaultInterpolatedStringHandler + { + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) => throw null; + public void Dispose() => throw null; + public override string ToString() => throw null; + public void AppendLiteral(string value) => throw null; + [System.Obsolete(""AppendFormatted is obsolete"", error: true)] + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; + } +} +"; + + var comp = CreateCompilation(new[] { code, interpolatedStringBuilder }); + comp.VerifyDiagnostics( + // (1,11): error CS0619: 'DefaultInterpolatedStringHandler.AppendFormatted(T, int, string)' is obsolete: 'AppendFormatted is obsolete' + // _ = $"base{(object)1}"; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "{(object)1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(T, int, string)", "AppendFormatted is obsolete").WithLocation(1, 13)); + } + + private const string UnmanagedCallersOnlyIl = @" +.class public auto ansi sealed beforefieldinit System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute extends [mscorlib]System.Attribute +{ + .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( + 01 00 40 00 00 00 01 00 54 02 09 49 6e 68 65 72 + 69 74 65 64 00 + ) + .field public class [mscorlib]System.Type[] CallConvs + .field public string EntryPoint + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Attribute::.ctor() + ret + } +}"; + + [Fact] + public void UnmanagedCallersOnlyAppendFormattedMethod() + { + var code = @"_ = $""""""{(object)1}"""""";"; + + var interpolatedStringBuilder = @" +.class public sequential ansi sealed beforefieldinit System.Runtime.CompilerServices.DefaultInterpolatedStringHandler + extends [mscorlib]System.ValueType +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [mscorlib]System.ObsoleteAttribute::.ctor(string, bool) = ( + 01 00 52 54 79 70 65 73 20 77 69 74 68 20 65 6d + 62 65 64 64 65 64 20 72 65 66 65 72 65 6e 63 65 + 73 20 61 72 65 20 6e 6f 74 20 73 75 70 70 6f 72 + 74 65 64 20 69 6e 20 74 68 69 73 20 76 65 72 73 + 69 6f 6e 20 6f 66 20 79 6f 75 72 20 63 6f 6d 70 + 69 6c 65 72 2e 01 00 00 + ) + .pack 0 + .size 1 + + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 literalLength, + int32 formattedCount + ) cil managed + { + ldnull + throw + } + + .method public hidebysig + instance void Dispose () cil managed + { + ldnull + throw + } + + .method public hidebysig virtual + instance string ToString () cil managed + { + ldnull + throw + } + + .method public hidebysig + instance void AppendLiteral ( + string 'value' + ) cil managed + { + ldnull + throw + } + + .method public hidebysig + instance void AppendFormatted ( + !!T hole, + [opt] int32 'alignment', + [opt] string format + ) cil managed + { + .custom instance void System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = ( + 01 00 00 00 + ) + .param [2] = int32(0) + .param [3] = nullref + ldnull + throw + } +} +"; + + var comp = CreateCompilationWithIL(code, ilSource: interpolatedStringBuilder + UnmanagedCallersOnlyIl); + comp.VerifyDiagnostics( + // (1,7): error CS0570: 'DefaultInterpolatedStringHandler.AppendFormatted(T, int, string)' is not supported by the language + // _ = $"{(object)1}"; + Diagnostic(ErrorCode.ERR_BindToBogus, "{(object)1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(T, int, string)").WithLocation(1, 9)); + } + + [Fact] + public void UnmanagedCallersOnlyToStringMethod() + { + var code = @"_ = $""""""{(object)1}"""""";"; + + var interpolatedStringBuilder = @" + +.class public sequential ansi sealed beforefieldinit System.Runtime.CompilerServices.DefaultInterpolatedStringHandler + extends [mscorlib]System.ValueType +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [mscorlib]System.ObsoleteAttribute::.ctor(string, bool) = ( + 01 00 52 54 79 70 65 73 20 77 69 74 68 20 65 6d + 62 65 64 64 65 64 20 72 65 66 65 72 65 6e 63 65 + 73 20 61 72 65 20 6e 6f 74 20 73 75 70 70 6f 72 + 74 65 64 20 69 6e 20 74 68 69 73 20 76 65 72 73 + 69 6f 6e 20 6f 66 20 79 6f 75 72 20 63 6f 6d 70 + 69 6c 65 72 2e 01 00 00 + ) + .pack 0 + .size 1 + + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 literalLength, + int32 formattedCount + ) cil managed + { + ldnull + throw + } + + .method public hidebysig instance string ToStringAndClear () cil managed + { + .custom instance void System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } + + .method public hidebysig + instance void AppendLiteral ( + string 'value' + ) cil managed + { + ldnull + throw + } + + .method public hidebysig + instance void AppendFormatted ( + !!T hole, + [opt] int32 'alignment', + [opt] string format + ) cil managed + { + .param [2] = int32(0) + .param [3] = nullref + ldnull + throw + } +} +"; + + var comp = CreateCompilationWithIL(code, ilSource: interpolatedStringBuilder + UnmanagedCallersOnlyIl); + comp.VerifyDiagnostics(); + comp.VerifyEmitDiagnostics( + // (1,5): error CS0570: 'DefaultInterpolatedStringHandler.ToStringAndClear()' is not supported by the language + // _ = $"{(object)1}"; + Diagnostic(ErrorCode.ERR_BindToBogus, @"$""""""{(object)1}""""""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()").WithLocation(1, 5)); + } + + [Theory] + [InlineData(@"$""""""{i}{s}""""""")] + [InlineData(@"$""""""{i}"""""" + $""""""{s}""""""")] + public void UnsupportedArgumentType(string expression) + { + var source = @" +unsafe +{ + int* i = null; + var s = new S(); + _ = " + expression + @"; +} +ref struct S +{ +}"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: true, useBoolReturns: false); + + var comp = CreateCompilation(new[] { source, interpolatedStringBuilder }, options: TestOptions.UnsafeReleaseExe, targetFramework: TargetFramework.NetCoreApp); + + if (expression.Contains('+')) + { + comp.VerifyDiagnostics( + // (6,13): error CS0306: The type 'int*' may not be used as a type argument + // _ = $"""{i}""" + $"""{s}"""; + Diagnostic(ErrorCode.ERR_BadTypeArgument, "{i}").WithArguments("int*").WithLocation(6, 13), + // (6,26): error CS0306: The type 'S' may not be used as a type argument + // _ = $"""{i}""" + $"""{s}"""; + Diagnostic(ErrorCode.ERR_BadTypeArgument, "{s}").WithArguments("S").WithLocation(6, 26)); + } + else + { + comp.VerifyDiagnostics( + // (6,13): error CS0306: The type 'int*' may not be used as a type argument + // _ = $"""{i}{s}"""; + Diagnostic(ErrorCode.ERR_BadTypeArgument, "{i}").WithArguments("int*").WithLocation(6, 13), + // (6,16): error CS0306: The type 'S' may not be used as a type argument + // _ = $"""{i}{s}"""; + Diagnostic(ErrorCode.ERR_BadTypeArgument, "{s}").WithArguments("S").WithLocation(6, 16)); + } + } + + [Theory] + [InlineData(@"$""""""{b switch { true => 1, false => null }}{(!b ? null : 2)}{default}{null}""""""")] + [InlineData(@"$""""""{b switch { true => 1, false => null }}"""""" + $""""""{(!b ? null : 2)}"""""" + $""""""{default}"""""" + $""""""{null}""""""")] + public void TargetTypedInterpolationHoles(string expression) + { + var source = @" +bool b = true; +System.Console.WriteLine(" + expression + @");"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @" +value:1 +value:2 +value: +value:"); + + verifier.VerifyIL("", @" +{ + // Code size 81 (0x51) + .maxstack 3 + .locals init (bool V_0, //b + object V_1, + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_2 + IL_0004: ldc.i4.0 + IL_0005: ldc.i4.4 + IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_000b: ldloc.0 + IL_000c: brfalse.s IL_0017 + IL_000e: ldc.i4.1 + IL_000f: box ""int"" + IL_0014: stloc.1 + IL_0015: br.s IL_0019 + IL_0017: ldnull + IL_0018: stloc.1 + IL_0019: ldloca.s V_2 + IL_001b: ldloc.1 + IL_001c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)"" + IL_0021: ldloca.s V_2 + IL_0023: ldloc.0 + IL_0024: brfalse.s IL_002e + IL_0026: ldc.i4.2 + IL_0027: box ""int"" + IL_002c: br.s IL_002f + IL_002e: ldnull + IL_002f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)"" + IL_0034: ldloca.s V_2 + IL_0036: ldnull + IL_0037: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"" + IL_003c: ldloca.s V_2 + IL_003e: ldnull + IL_003f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"" + IL_0044: ldloca.s V_2 + IL_0046: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_004b: call ""void System.Console.WriteLine(string)"" + IL_0050: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{(null, default)}{new()}""""""")] + [InlineData(@"$""""""{(null, default)}"""""" + $""""""{new()}""""""")] + public void TargetTypedInterpolationHoles_Errors(string expression) + { + var source = @"System.Console.WriteLine(" + expression + @");"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + var comp = CreateCompilation(new[] { source, interpolatedStringBuilder }, parseOptions: TestOptions.Regular9); + + 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. + // System.Console.WriteLine($"""{(null, default)}""" + $"""{new()}"""); + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{(null, default)}""""""").WithArguments("raw string literals").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. + // System.Console.WriteLine($"""{(null, default)}""" + $"""{new()}"""); + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{new()}""""""").WithArguments("raw string literals").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)); + } + 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. + // System.Console.WriteLine($"""{(null, default)}{new()}"""); + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{(null, default)}{new()}""""""").WithArguments("raw string literals").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,48): 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, 48)); + } + } + + [Fact] + public void RefTernary() + { + var source = @" +bool b = true; +int i = 1; +System.Console.WriteLine($""""""{(!b ? ref i : ref i)}"""""");"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"value:1"); + } + + [Fact] + public void NestedInterpolatedStrings_01() + { + var source = @" +int i = 1; +System.Console.WriteLine($""""""{$""""""{i}""""""}"""""");"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"value:1"); + + verifier.VerifyIL("", @" +{ + // Code size 32 (0x20) + .maxstack 3 + .locals init (int V_0, //i + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.0 + IL_0005: ldc.i4.1 + IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_000b: ldloca.s V_1 + IL_000d: ldloc.0 + IL_000e: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0013: ldloca.s V_1 + IL_0015: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_001a: call ""void System.Console.WriteLine(string)"" + IL_001f: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{$""""""{i1}""""""}{$""""""{i2}""""""}""""""")] + [InlineData(@"$""""""{$""""""{i1}""""""}"""""" + $""""""{$""""""{i2}""""""}""""""")] + public void NestedInterpolatedStrings_02(string expression) + { + var source = @" +int i1 = 1; +int i2 = 2; +System.Console.WriteLine(" + expression + @");"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @" +value:1 +value:2"); + + verifier.VerifyIL("", @" +{ + // Code size 63 (0x3f) + .maxstack 4 + .locals init (int V_0, //i1 + int V_1, //i2 + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldc.i4.2 + IL_0003: stloc.1 + IL_0004: ldloca.s V_2 + IL_0006: ldc.i4.0 + IL_0007: ldc.i4.1 + IL_0008: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_000d: ldloca.s V_2 + IL_000f: ldloc.0 + IL_0010: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0015: ldloca.s V_2 + IL_0017: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_001c: ldloca.s V_2 + IL_001e: ldc.i4.0 + IL_001f: ldc.i4.1 + IL_0020: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0025: ldloca.s V_2 + IL_0027: ldloc.1 + IL_0028: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_002d: ldloca.s V_2 + IL_002f: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0034: call ""string string.Concat(string, string)"" + IL_0039: call ""void System.Console.WriteLine(string)"" + IL_003e: ret +} +"); + } + + [Fact] + public void ExceptionFilter_01() + { + var source = @" +using System; + +int i = 1; +try +{ + Console.WriteLine(""Starting try""); + throw new MyException { Prop = i }; +} +// Test DefaultInterpolatedStringHandler renders specially, so we're actually comparing to ""value:Prop"" plus some whitespace +catch (MyException e) when (e.ToString() == $""""""{i}"""""".Trim()) +{ + Console.WriteLine(""Caught""); +} + +class MyException : Exception +{ + public int Prop { get; set; } + public override string ToString() => ""value:"" + Prop.ToString(); +}"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @" +Starting try +Caught"); + + verifier.VerifyIL("", @" +{ + // Code size 95 (0x5f) + .maxstack 4 + .locals init (int V_0, //i + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + .try + { + IL_0002: ldstr ""Starting try"" + IL_0007: call ""void System.Console.WriteLine(string)"" + IL_000c: newobj ""MyException..ctor()"" + IL_0011: dup + IL_0012: ldloc.0 + IL_0013: callvirt ""void MyException.Prop.set"" + IL_0018: throw + } + filter + { + IL_0019: isinst ""MyException"" + IL_001e: dup + IL_001f: brtrue.s IL_0025 + IL_0021: pop + IL_0022: ldc.i4.0 + IL_0023: br.s IL_004f + IL_0025: callvirt ""string object.ToString()"" + IL_002a: ldloca.s V_1 + IL_002c: ldc.i4.0 + IL_002d: ldc.i4.1 + IL_002e: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0033: ldloca.s V_1 + IL_0035: ldloc.0 + IL_0036: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_003b: ldloca.s V_1 + IL_003d: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0042: callvirt ""string string.Trim()"" + IL_0047: call ""bool string.op_Equality(string, string)"" + IL_004c: ldc.i4.0 + IL_004d: cgt.un + IL_004f: endfilter + } // end filter + { // handler + IL_0051: pop + IL_0052: ldstr ""Caught"" + IL_0057: call ""void System.Console.WriteLine(string)"" + IL_005c: leave.s IL_005e + } + IL_005e: ret +} +"); + } + + [ConditionalFact(typeof(MonoOrCoreClrOnly), typeof(NoIOperationValidation))] + public void ExceptionFilter_02() + { + var source = @" +using System; + +ReadOnlySpan s = new char[] { 'i' }; +try +{ + Console.WriteLine(""Starting try""); + throw new MyException { Prop = s.ToString() }; +} +// Test DefaultInterpolatedStringHandler renders specially, so we're actually comparing to ""value:Prop"" plus some whitespace +catch (MyException e) when (e.ToString() == $""""""{s}"""""".Trim()) +{ + Console.WriteLine(""Caught""); +} + +class MyException : Exception +{ + public string Prop { get; set; } + public override string ToString() => ""value:"" + Prop.ToString(); +}"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: false, useBoolReturns: false); + + var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, targetFramework: TargetFramework.NetCoreApp, expectedOutput: @" +Starting try +Caught"); + + + verifier.VerifyIL("", @" +{ + // Code size 122 (0x7a) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //s + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: newarr ""char"" + IL_0006: dup + IL_0007: ldc.i4.0 + IL_0008: ldc.i4.s 105 + IL_000a: stelem.i2 + IL_000b: call ""System.ReadOnlySpan System.ReadOnlySpan.op_Implicit(char[])"" + IL_0010: stloc.0 + .try + { + IL_0011: ldstr ""Starting try"" + IL_0016: call ""void System.Console.WriteLine(string)"" + IL_001b: newobj ""MyException..ctor()"" + IL_0020: dup + IL_0021: ldloca.s V_0 + IL_0023: constrained. ""System.ReadOnlySpan"" + IL_0029: callvirt ""string object.ToString()"" + IL_002e: callvirt ""void MyException.Prop.set"" + IL_0033: throw + } + filter + { + IL_0034: isinst ""MyException"" + IL_0039: dup + IL_003a: brtrue.s IL_0040 + IL_003c: pop + IL_003d: ldc.i4.0 + IL_003e: br.s IL_006a + IL_0040: callvirt ""string object.ToString()"" + IL_0045: ldloca.s V_1 + IL_0047: ldc.i4.0 + IL_0048: ldc.i4.1 + IL_0049: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_004e: ldloca.s V_1 + IL_0050: ldloc.0 + IL_0051: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan)"" + IL_0056: ldloca.s V_1 + IL_0058: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_005d: callvirt ""string string.Trim()"" + IL_0062: call ""bool string.op_Equality(string, string)"" + IL_0067: ldc.i4.0 + IL_0068: cgt.un + IL_006a: endfilter + } // end filter + { // handler + IL_006c: pop + IL_006d: ldstr ""Caught"" + IL_0072: call ""void System.Console.WriteLine(string)"" + IL_0077: leave.s IL_0079 + } + IL_0079: ret +} +"); + } + + [ConditionalTheory(typeof(MonoOrCoreClrOnly), typeof(NoIOperationValidation))] + [InlineData(@"$""""""{s}{c}""""""")] + [InlineData(@"$""""""{s}"""""" + $""""""{c}""""""")] + public void ImplicitUserDefinedConversionInHole(string expression) + { + var source = @" +using System; + +S s = default; +C c = new C(); +Console.WriteLine(" + expression + @"); + +ref struct S +{ + public static implicit operator ReadOnlySpan(S s) => ""S converted""; +} +class C +{ + public static implicit operator ReadOnlySpan(C s) => ""C converted""; +}"; + + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: false, useBoolReturns: false); + + var comp = CreateCompilation(new[] { source, interpolatedStringBuilder }, + targetFramework: TargetFramework.NetCoreApp); + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. { Offset = 10 } + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:S converted +value:C", verify: Verification.FailsILVerify); + + verifier.VerifyIL("", @" +{ + // Code size 57 (0x39) + .maxstack 3 + .locals init (S V_0, //s + C V_1, //c + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2) + IL_0000: ldloca.s V_0 + IL_0002: initobj ""S"" + IL_0008: newobj ""C..ctor()"" + IL_000d: stloc.1 + IL_000e: ldloca.s V_2 + IL_0010: ldc.i4.0 + IL_0011: ldc.i4.2 + IL_0012: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0017: ldloca.s V_2 + IL_0019: ldloc.0 + IL_001a: call ""System.ReadOnlySpan S.op_Implicit(S)"" + IL_001f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan)"" + IL_0024: ldloca.s V_2 + IL_0026: ldloc.1 + IL_0027: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(C)"" + IL_002c: ldloca.s V_2 + IL_002e: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0033: call ""void System.Console.WriteLine(string)"" + IL_0038: ret +} +"); + } + + [Fact] + public void ExplicitUserDefinedConversionInHole() + { + var source = @" +using System; + +S s = default; +Console.WriteLine($""""""{s}""""""); + +ref struct S +{ + public static explicit operator ReadOnlySpan(S s) => ""S converted""; +} +"; + var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: false, useBoolReturns: false); + + var comp = CreateCompilation(new[] { source, interpolatedStringBuilder }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (5,21): error CS0306: The type 'S' may not be used as a type argument + // Console.WriteLine($"{s}"); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "{s}").WithArguments("S").WithLocation(5, 23)); + } + + [Theory] + [InlineData(@"$""""""Text{1}""""""")] + [InlineData(@"$""""""Text"""""" + $""""""{1}""""""")] + public void ImplicitUserDefinedConversionInLiteral(string expression) + { + var source = @" +using System; + +Console.WriteLine(" + expression + @"); + +public struct CustomStruct +{ + public static implicit operator CustomStruct(string s) => new CustomStruct { S = s }; + public string S { get; set; } + public override string ToString() => ""literal:"" + S; +} + +namespace System.Runtime.CompilerServices +{ + using System.Text; + public ref struct DefaultInterpolatedStringHandler + { + private readonly StringBuilder _builder; + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) + { + _builder = new StringBuilder(); + } + public string ToStringAndClear() => _builder.ToString(); + public void AppendLiteral(CustomStruct s) => _builder.AppendLine(s.ToString()); + public void AppendFormatted(object o) => _builder.AppendLine(""value:"" + o.ToString()); + } +}"; + + var verifier = CompileAndVerify(source, expectedOutput: @" +literal:Text +value:1"); + verifier.VerifyIL("", @" +{ + // Code size 52 (0x34) + .maxstack 3 + .locals init (System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_0) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.4 + IL_0003: ldc.i4.1 + IL_0004: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0009: ldloca.s V_0 + IL_000b: ldstr ""Text"" + IL_0010: call ""CustomStruct CustomStruct.op_Implicit(string)"" + IL_0015: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(CustomStruct)"" + IL_001a: ldloca.s V_0 + IL_001c: ldc.i4.1 + IL_001d: box ""int"" + IL_0022: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)"" + IL_0027: ldloca.s V_0 + IL_0029: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_002e: call ""void System.Console.WriteLine(string)"" + IL_0033: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""Text{1}""""""")] + [InlineData(@"$""""""Text"""""" + $""""""{1}""""""")] + public void ExplicitUserDefinedConversionInLiteral(string expression) + { + var source = @" +using System; + +Console.WriteLine(" + expression + @"); + +public struct CustomStruct +{ + public static explicit operator CustomStruct(string s) => new CustomStruct { S = s }; + public string S { get; set; } + public override string ToString() => ""literal:"" + S; +} + +namespace System.Runtime.CompilerServices +{ + using System.Text; + public ref struct DefaultInterpolatedStringHandler + { + private readonly StringBuilder _builder; + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) + { + _builder = new StringBuilder(); + } + public string ToStringAndClear() => _builder.ToString(); + public void AppendLiteral(CustomStruct s) => _builder.AppendLine(s.ToString()); + public void AppendFormatted(object o) => _builder.AppendLine(""value:"" + o.ToString()); + } +}"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (4,21): error CS1503: Argument 1: cannot convert from 'string' to 'CustomStruct' + // Console.WriteLine($"Text{1}"); + Diagnostic(ErrorCode.ERR_BadArgType, "Text").WithArguments("1", "string", "CustomStruct").WithLocation(4, 23)); + } + + [Theory] + [InlineData(@"$""""""Text{1}""""""")] + [InlineData(@"$""""""Text"""""" + $""""""{1}""""""")] + public void InvalidBuilderReturnType(string expression) + { + var source = @" +using System; + +Console.WriteLine(" + expression + @"); + +namespace System.Runtime.CompilerServices +{ + using System.Text; + public ref struct DefaultInterpolatedStringHandler + { + private readonly StringBuilder _builder; + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) + { + _builder = new StringBuilder(); + } + public string ToStringAndClear() => _builder.ToString(); + public int AppendLiteral(string s) => 0; + public int AppendFormatted(object o) => 0; + } +}"; + + var comp = CreateCompilation(source); + + if (expression.Contains('+')) + { + comp.VerifyDiagnostics( + // (4,23): error CS8941: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendLiteral(string)' is malformed. It does not return 'void' or 'bool'. + // Console.WriteLine($"""Text""" + $"""{1}"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "Text").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)").WithLocation(4, 23), + // (4,37): error CS8941: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendFormatted(object)' is malformed. It does not return 'void' or 'bool'. + // Console.WriteLine($"""Text""" + $"""{1}"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)").WithLocation(4, 37)); + } + else + { + comp.VerifyDiagnostics( + // (4,23): error CS8941: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendLiteral(string)' is malformed. It does not return 'void' or 'bool'. + // Console.WriteLine($"""Text{1}"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "Text").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)").WithLocation(4, 23), + // (4,27): error CS8941: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendFormatted(object)' is malformed. It does not return 'void' or 'bool'. + // Console.WriteLine($"""Text{1}"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)").WithLocation(4, 27)); + } + } + + [Fact] + public void MissingAppendMethods() + { + var source = @" +using System.Runtime.CompilerServices; + +CustomHandler c = $""""""Literal{1}""""""; + +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) { } +} +"; + + var comp = CreateCompilation(new[] { source, InterpolatedStringHandlerAttribute }); + comp.VerifyDiagnostics( + // (4,21): error CS1061: 'CustomHandler' does not contain a definition for 'AppendLiteral' and no accessible extension method 'AppendLiteral' accepting a first argument of type 'CustomHandler' could be found (are you missing a using directive or an assembly reference?) + // CustomHandler c = $"Literal{1}"; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Literal").WithArguments("CustomHandler", "AppendLiteral").WithLocation(4, 23), + // (4,21): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. + // CustomHandler c = $"Literal{1}"; + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "Literal").WithArguments("?.()").WithLocation(4, 23), + // (4,28): error CS1061: 'CustomHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'CustomHandler' could be found (are you missing a using directive or an assembly reference?) + // CustomHandler c = $"Literal{1}"; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{1}").WithArguments("CustomHandler", "AppendFormatted").WithLocation(4, 30), + // (4,28): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'. + // CustomHandler c = $"Literal{1}"; + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{1}").WithArguments("?.()").WithLocation(4, 30)); + } + + [Fact] + public void MissingBoolType() + { + var handlerSource = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true); + var handlerRef = CreateCompilation(handlerSource).EmitToImageReference(); + + var source = @"CustomHandler c = $""""""Literal{1}"""""";"; + + var comp = CreateCompilation(source, references: new[] { handlerRef }); + comp.MakeTypeMissing(SpecialType.System_Boolean); + comp.VerifyDiagnostics( + // (1,19): error CS0518: Predefined type 'System.Boolean' is not defined or imported + // CustomHandler c = $"Literal{1}"; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"$""""""Literal{1}""""""").WithArguments("System.Boolean").WithLocation(1, 19)); + } + + [Fact] + public void MissingVoidType() + { + var handlerSource = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false); + var handlerRef = CreateCompilation(handlerSource).EmitToImageReference(); + + var source = @" +class C +{ + public bool M() + { + CustomHandler c = $""""""Literal{1}""""""; + return true; + } +} +"; + + var comp = CreateCompilation(source, references: new[] { handlerRef }); + comp.MakeTypeMissing(SpecialType.System_Void); + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [InlineData(@"$""""""Text{1}""""""", @"$""""""{1}Text""""""")] + [InlineData(@"$""""""Text"""""" + $""""""{1}""""""", @"$""""""{1}"""""" + $""""""Text""""""")] + public void MixedBuilderReturnTypes_01(string expression1, string expression2) + { + var source = @" +using System; + +Console.WriteLine(" + expression1 + @"); +Console.WriteLine(" + expression2 + @"); + +namespace System.Runtime.CompilerServices +{ + using System.Text; + public ref struct DefaultInterpolatedStringHandler + { + private readonly StringBuilder _builder; + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) + { + _builder = new StringBuilder(); + } + public string ToStringAndClear() => _builder.ToString(); + public bool AppendLiteral(string s) => true; + public void AppendFormatted(object o) { } + } +}"; + + var comp = CreateCompilation(source); + + if (expression1.Contains('+')) + { + comp.VerifyDiagnostics( + // (4,37): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendFormatted(object)' has inconsistent return type. Expected to return 'bool'. + // Console.WriteLine($"""Text""" + $"""{1}"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "{1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)", "bool").WithLocation(4, 37), + // (5,36): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendLiteral(string)' has inconsistent return type. Expected to return 'void'. + // Console.WriteLine($"""{1}""" + $"""Text"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "Text").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)", "void").WithLocation(5, 36)); + } + else + { + comp.VerifyDiagnostics( + // (4,27): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendFormatted(object)' has inconsistent return type. Expected to return 'bool'. + // Console.WriteLine($"""Text{1}"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "{1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)", "bool").WithLocation(4, 27), + // (5,26): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendLiteral(string)' has inconsistent return type. Expected to return 'void'. + // Console.WriteLine($"""{1}Text"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "Text").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)", "void").WithLocation(5, 26)); + } + } + + [Theory] + [InlineData(@"$""""""Text{1}""""""", @"$""""""{1}Text""""""")] + [InlineData(@"$""""""Text"""""" + $""""""{1}""""""", @"$""""""{1}"""""" + $""""""Text""""""")] + public void MixedBuilderReturnTypes_02(string expression1, string expression2) + { + var source = @" +using System; + +Console.WriteLine(" + expression1 + @"); +Console.WriteLine(" + expression2 + @"); + +namespace System.Runtime.CompilerServices +{ + using System.Text; + public ref struct DefaultInterpolatedStringHandler + { + private readonly StringBuilder _builder; + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) + { + _builder = new StringBuilder(); + } + public string ToStringAndClear() => _builder.ToString(); + public void AppendLiteral(string s) { } + public bool AppendFormatted(object o) => true; + } +}"; + + var comp = CreateCompilation(source); + if (expression1.Contains('+')) + { + comp.VerifyDiagnostics( + // (4,37): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendFormatted(object)' has inconsistent return type. Expected to return 'void'. + // Console.WriteLine($"""Text""" + $"""{1}"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "{1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)", "void").WithLocation(4, 37), + // (5,36): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendLiteral(string)' has inconsistent return type. Expected to return 'bool'. + // Console.WriteLine($"""{1}""" + $"""Text"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "Text").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)", "bool").WithLocation(5, 36)); + } + else + { + comp.VerifyDiagnostics( + // (4,27): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendFormatted(object)' has inconsistent return type. Expected to return 'void'. + // Console.WriteLine($"""Text{1}"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "{1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)", "void").WithLocation(4, 27), + // (5,26): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendLiteral(string)' has inconsistent return type. Expected to return 'bool'. + // Console.WriteLine($"""{1}Text"""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "Text").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)", "bool").WithLocation(5, 26)); + } + } + + [Fact] + public void MixedBuilderReturnTypes_03() + { + var source = @" +using System; + +Console.WriteLine($""""""{1}""""""); + +namespace System.Runtime.CompilerServices +{ + using System.Text; + public ref struct DefaultInterpolatedStringHandler + { + private readonly StringBuilder _builder; + public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) + { + _builder = new StringBuilder(); + } + public string ToStringAndClear() => _builder.ToString(); + public bool AppendLiteral(string s) => true; + public void AppendFormatted(object o) + { + _builder.AppendLine(""value:"" + o.ToString()); + } + } +}"; + + CompileAndVerify(source, expectedOutput: "value:1"); + } + + [Fact] + public void MixedBuilderReturnTypes_04() + { + var source = @" +using System; +using System.Text; +using System.Runtime.CompilerServices; + +Console.WriteLine((CustomHandler)$""""""l""""""); + +[InterpolatedStringHandler] +public class CustomHandler +{ + private readonly StringBuilder _builder; + public CustomHandler(int literalLength, int formattedCount) + { + _builder = new StringBuilder(); + } + public override string ToString() => _builder.ToString(); + public bool AppendFormatted(object o) => true; + public void AppendLiteral(string s) + { + _builder.AppendLine(""literal:"" + s.ToString()); + } +} +"; + + CompileAndVerify(new[] { source, InterpolatedStringHandlerAttribute }, expectedOutput: "literal:l"); + } + + private static void VerifyInterpolatedStringExpression(CSharpCompilation comp, string handlerType = "CustomHandler") + { + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var descendentNodes = tree.GetRoot().DescendantNodes(); + var interpolatedString = + (ExpressionSyntax)descendentNodes.OfType() + .Where(b => b.DescendantNodes().OfType().Any()) + .FirstOrDefault() + ?? descendentNodes.OfType().Single(); + var semanticInfo = model.GetSemanticInfoSummary(interpolatedString); + + Assert.Equal(SpecialType.System_String, semanticInfo.Type.SpecialType); + Assert.Equal(handlerType, semanticInfo.ConvertedType.ToTestDisplayString()); + Assert.Equal(ConversionKind.InterpolatedStringHandler, semanticInfo.ImplicitConversion.Kind); + Assert.True(semanticInfo.ImplicitConversion.Exists); + Assert.True(semanticInfo.ImplicitConversion.IsValid); + Assert.True(semanticInfo.ImplicitConversion.IsInterpolatedStringHandler); + Assert.Null(semanticInfo.ImplicitConversion.Method); + + if (interpolatedString is BinaryExpressionSyntax) + { + Assert.False(semanticInfo.ConstantValue.HasValue); + AssertEx.Equal("System.String System.String.op_Addition(System.String left, System.String right)", semanticInfo.Symbol.ToTestDisplayString()); + } + + // https://github.com/dotnet/roslyn/issues/54505 Assert IConversionOperation.IsImplicit when IOperation is implemented for interpolated strings. + } + + private CompilationVerifier CompileAndVerifyOnCorrectPlatforms(CSharpCompilation compilation, string expectedOutput) + => CompileAndVerify( + compilation, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? expectedOutput : null, + verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped); + + [Theory] + [CombinatorialData] + public void CustomHandlerLocal([CombinatorialValues("class", "struct")] string type, bool useBoolReturns, + [CombinatorialValues(@"$""""""Literal{1,2:f}""""""", @"$""""""Literal"""""" + $""""""{1,2:f}""""""")] string expression) + { + var code = @" +CustomHandler builder = " + expression + @"; +System.Console.WriteLine(builder.ToString());"; + + var builder = GetInterpolatedStringCustomHandlerType("CustomHandler", type, useBoolReturns); + var comp = CreateCompilation(new[] { code, builder }); + VerifyInterpolatedStringExpression(comp); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +literal:Literal +value:1 +alignment:2 +format:f"); + + verifier.VerifyIL("", getIl()); + + string getIl() => (type, useBoolReturns) switch + { + (type: "struct", useBoolReturns: true) => @" +{ + // Code size 67 (0x43) + .maxstack 4 + .locals init (CustomHandler V_0, //builder + CustomHandler V_1) + IL_0000: ldloca.s V_1 + IL_0002: ldc.i4.7 + IL_0003: ldc.i4.1 + IL_0004: call ""CustomHandler..ctor(int, int)"" + IL_0009: ldloca.s V_1 + IL_000b: ldstr ""Literal"" + IL_0010: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0015: brfalse.s IL_002c + IL_0017: ldloca.s V_1 + IL_0019: ldc.i4.1 + IL_001a: box ""int"" + IL_001f: ldc.i4.2 + IL_0020: ldstr ""f"" + IL_0025: call ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_002a: br.s IL_002d + IL_002c: ldc.i4.0 + IL_002d: pop + IL_002e: ldloc.1 + IL_002f: stloc.0 + IL_0030: ldloca.s V_0 + IL_0032: constrained. ""CustomHandler"" + IL_0038: callvirt ""string object.ToString()"" + IL_003d: call ""void System.Console.WriteLine(string)"" + IL_0042: ret +} +", + (type: "struct", useBoolReturns: false) => @" +{ + // Code size 61 (0x3d) + .maxstack 4 + .locals init (CustomHandler V_0, //builder + CustomHandler V_1) + IL_0000: ldloca.s V_1 + IL_0002: ldc.i4.7 + IL_0003: ldc.i4.1 + IL_0004: call ""CustomHandler..ctor(int, int)"" + IL_0009: ldloca.s V_1 + IL_000b: ldstr ""Literal"" + IL_0010: call ""void CustomHandler.AppendLiteral(string)"" + IL_0015: ldloca.s V_1 + IL_0017: ldc.i4.1 + IL_0018: box ""int"" + IL_001d: ldc.i4.2 + IL_001e: ldstr ""f"" + IL_0023: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0028: ldloc.1 + IL_0029: stloc.0 + IL_002a: ldloca.s V_0 + IL_002c: constrained. ""CustomHandler"" + IL_0032: callvirt ""string object.ToString()"" + IL_0037: call ""void System.Console.WriteLine(string)"" + IL_003c: ret +} +", + (type: "class", useBoolReturns: true) => @" +{ + // Code size 55 (0x37) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldstr ""Literal"" + IL_000e: callvirt ""bool CustomHandler.AppendLiteral(string)"" + IL_0013: brfalse.s IL_0029 + IL_0015: ldloc.0 + IL_0016: ldc.i4.1 + IL_0017: box ""int"" + IL_001c: ldc.i4.2 + IL_001d: ldstr ""f"" + IL_0022: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_0027: br.s IL_002a + IL_0029: ldc.i4.0 + IL_002a: pop + IL_002b: ldloc.0 + IL_002c: callvirt ""string object.ToString()"" + IL_0031: call ""void System.Console.WriteLine(string)"" + IL_0036: ret +} +", + (type: "class", useBoolReturns: false) => @" +{ + // Code size 47 (0x2f) + .maxstack 5 + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: dup + IL_0008: ldstr ""Literal"" + IL_000d: callvirt ""void CustomHandler.AppendLiteral(string)"" + IL_0012: dup + IL_0013: ldc.i4.1 + IL_0014: box ""int"" + IL_0019: ldc.i4.2 + IL_001a: ldstr ""f"" + IL_001f: callvirt ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0024: callvirt ""string object.ToString()"" + IL_0029: call ""void System.Console.WriteLine(string)"" + IL_002e: ret +} +", + _ => throw ExceptionUtilities.Unreachable + }; + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void CustomHandlerMethodArgument(string expression) + { + var code = @" +M(" + expression + @"); +void M(CustomHandler b) +{ + System.Console.WriteLine(b.ToString()); +}"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL(@"", @" +{ + // Code size 50 (0x32) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldc.i4.1 + IL_000a: box ""int"" + IL_000f: ldc.i4.2 + IL_0010: ldstr ""f"" + IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_001a: brfalse.s IL_0029 + IL_001c: ldloc.0 + IL_001d: ldstr ""Literal"" + IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)"" + IL_0027: br.s IL_002a + IL_0029: ldc.i4.0 + IL_002a: pop + IL_002b: ldloc.0 + IL_002c: call ""void Program.<
$>g__M|0_0(CustomHandler)"" + IL_0031: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"($""""""{1,2:f}"""""" + $""""""Literal"""""")")] + public void ExplicitHandlerCast_InCode(string expression) + { + var code = @"System.Console.WriteLine((CustomHandler)" + expression + @");"; + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: false) }); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + SyntaxNode syntax = tree.GetRoot().DescendantNodes().OfType().Single(); + var semanticInfo = model.GetSemanticInfoSummary(syntax); + Assert.Equal("CustomHandler", semanticInfo.Type.ToTestDisplayString()); + Assert.Equal(SpecialType.System_Object, semanticInfo.ConvertedType.SpecialType); + Assert.Equal(ConversionKind.ImplicitReference, semanticInfo.ImplicitConversion.Kind); + + syntax = ((CastExpressionSyntax)syntax).Expression; + Assert.Equal(expression, syntax.ToString()); + semanticInfo = model.GetSemanticInfoSummary(syntax); + Assert.Equal(SpecialType.System_String, semanticInfo.Type.SpecialType); + Assert.Equal(SpecialType.System_String, semanticInfo.ConvertedType.SpecialType); + Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind); + + // https://github.com/dotnet/roslyn/issues/54505 Assert cast is explicit after IOperation is implemented + + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 42 (0x2a) + .maxstack 5 + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: dup + IL_0008: ldc.i4.1 + IL_0009: box ""int"" + IL_000e: ldc.i4.2 + IL_000f: ldstr ""f"" + IL_0014: callvirt ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0019: dup + IL_001a: ldstr ""Literal"" + IL_001f: callvirt ""void CustomHandler.AppendLiteral(string)"" + IL_0024: call ""void System.Console.WriteLine(object)"" + IL_0029: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{""""""Literal""""""}""""""")] + [InlineData(@"$""""""{""""""Lit""""""}"""""" + $""""""{""""""eral""""""}""""""")] + public void StringPreferredOverHandlerConversionForConstant(string expression) + { + var code = @" +C.M(" + expression + @"); +class C +{ + public static void M(CustomHandler b) + { + throw null; + } + public static void M(string s) + { + System.Console.WriteLine(s); + } +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + var verifier = CompileAndVerify(comp, expectedOutput: @"Literal"); + + verifier.VerifyIL(@"", @" +{ + // Code size 11 (0xb) + .maxstack 1 + IL_0000: ldstr ""Literal"" + IL_0005: call ""void C.M(string)"" + IL_000a: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1}{2}""""""")] + [InlineData(@"$""""""{1}"""""" + $""""""{2}""""""")] + public void HandlerConversionPreferredOverStringForNonConstant_AttributeConstructor(string expression) + { + var code = @" +using System; + +[Attr(" + expression + @")] +class Attr : Attribute +{ + public Attr(string s) {} + public Attr(CustomHandler c) {} +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + comp.VerifyDiagnostics( + // (4,2): error CS0181: Attribute constructor parameter 'c' has type 'CustomHandler', which is not a valid attribute parameter type + // [Attr($"{1}{2}")] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "Attr").WithArguments("c", "CustomHandler").WithLocation(4, 2)); + VerifyInterpolatedStringExpression(comp); + + var attr = comp.SourceAssembly.SourceModule.GlobalNamespace.GetTypeMember("Attr"); + Assert.Equal("Attr..ctor(CustomHandler c)", attr.GetAttributes().Single().AttributeConstructor.ToTestDisplayString()); + } + + [Theory] + [InlineData(@"$""""""{""""""Literal""""""}""""""")] + [InlineData(@"$""""""{""""""Lit""""""}"""""" + $""""""{""""""eral""""""}""""""")] + public void StringPreferredOverHandlerConversionForConstant_AttributeConstructor(string expression) + { + var code = @" +using System; + +[Attr(" + expression + @")] +class Attr : Attribute +{ + public Attr(string s) {} + public Attr(CustomHandler c) {} +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate); + + void validate(ModuleSymbol m) + { + var attr = m.GlobalNamespace.GetTypeMember("Attr"); + Assert.Equal("Attr..ctor(System.String s)", attr.GetAttributes().Single().AttributeConstructor.ToTestDisplayString()); + } + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void MultipleBuilderTypes(string expression) + { + var code = @" +C.M(" + expression + @"); + +class C +{ + public static void M(CustomHandler1 c) => throw null; + public static void M(CustomHandler2 c) => throw null; +}"; + + var comp = CreateCompilation(new[] + { + code, + GetInterpolatedStringCustomHandlerType("CustomHandler1", "struct", useBoolReturns: false), + GetInterpolatedStringCustomHandlerType("CustomHandler2", "struct", useBoolReturns: false, includeOneTimeHelpers: false) + }); + + comp.VerifyDiagnostics( + // (2,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(CustomHandler1)' and 'C.M(CustomHandler2)' + // C.M($""); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(CustomHandler1)", "C.M(CustomHandler2)").WithLocation(2, 3)); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void GenericOverloadResolution_01(string expression) + { + var code = @" +using System; + +C.M(" + expression + @"); + +class C +{ + public static void M(T t) => throw null; + public static void M(CustomHandler c) => Console.WriteLine(c); +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 50 (0x32) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldc.i4.1 + IL_000a: box ""int"" + IL_000f: ldc.i4.2 + IL_0010: ldstr ""f"" + IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_001a: brfalse.s IL_0029 + IL_001c: ldloc.0 + IL_001d: ldstr ""Literal"" + IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)"" + IL_0027: br.s IL_002a + IL_0029: ldc.i4.0 + IL_002a: pop + IL_002b: ldloc.0 + IL_002c: call ""void C.M(CustomHandler)"" + IL_0031: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void GenericOverloadResolution_02(string expression) + { + var code = @" +using System; + +C.M(" + expression + @"); + +class C +{ + public static void M(T t) where T : CustomHandler => throw null; + public static void M(CustomHandler c) => Console.WriteLine(c); +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 50 (0x32) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldc.i4.1 + IL_000a: box ""int"" + IL_000f: ldc.i4.2 + IL_0010: ldstr ""f"" + IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_001a: brfalse.s IL_0029 + IL_001c: ldloc.0 + IL_001d: ldstr ""Literal"" + IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)"" + IL_0027: br.s IL_002a + IL_0029: ldc.i4.0 + IL_002a: pop + IL_002b: ldloc.0 + IL_002c: call ""void C.M(CustomHandler)"" + IL_0031: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void GenericOverloadResolution_03(string expression) + { + var code = @" +C.M(" + expression + @"); + +class C +{ + public static void M(T t) where T : CustomHandler => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + comp.VerifyDiagnostics( + // (2,3): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'C.M(T)'. There is no implicit reference conversion from 'string' to 'CustomHandler'. + // C.M($"{1,2:f}Literal"); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("C.M(T)", "CustomHandler", "T", "string").WithLocation(2, 3)); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void GenericInference_01(string expression) + { + var code = @" +C.M(" + expression + @", default(CustomHandler)); +C.M(default(CustomHandler), " + expression + @"); + +class C +{ + public static void M(T t1, T t2) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (2,3): error CS0411: The type arguments for method 'C.M(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // C.M($"{1,2:f}Literal", default(CustomHandler)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M(T, T)").WithLocation(2, 3), + // (3,3): error CS0411: The type arguments for method 'C.M(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // C.M(default(CustomHandler), $"{1,2:f}Literal"); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M(T, T)").WithLocation(3, 3)); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void GenericInference_02(string expression) + { + var code = @" +using System; +C.M(default(CustomHandler), () => " + expression + @"); + +class C +{ + public static void M(T t1, Func t2) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + comp.VerifyDiagnostics( + // (3,3): error CS0411: The type arguments for method 'C.M(T, Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // C.M(default(CustomHandler), () => $"{1,2:f}Literal"); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M(T, System.Func)").WithLocation(3, 3)); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void GenericInference_03(string expression) + { + var code = @" +using System; +C.M(" + expression + @", default(CustomHandler)); + +class C +{ + public static void M(T t1, T t2) => Console.WriteLine(t1); +} + +partial class CustomHandler +{ + public static implicit operator CustomHandler(string s) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: true) }); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 51 (0x33) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldc.i4.1 + IL_000a: box ""int"" + IL_000f: ldc.i4.2 + IL_0010: ldstr ""f"" + IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_001a: brfalse.s IL_0029 + IL_001c: ldloc.0 + IL_001d: ldstr ""Literal"" + IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)"" + IL_0027: br.s IL_002a + IL_0029: ldc.i4.0 + IL_002a: pop + IL_002b: ldloc.0 + IL_002c: ldnull + IL_002d: call ""void C.M(CustomHandler, CustomHandler)"" + IL_0032: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void GenericInference_04(string expression) + { + var code = @" +using System; +C.M(default(CustomHandler), () => " + expression + @"); + +class C +{ + public static void M(T t1, Func t2) => Console.WriteLine(t2()); +} + +partial class CustomHandler +{ + public static implicit operator CustomHandler(string s) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: true) }); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("Program.<>c.<
$>b__0_0()", @" +{ + // Code size 45 (0x2d) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldc.i4.1 + IL_000a: box ""int"" + IL_000f: ldc.i4.2 + IL_0010: ldstr ""f"" + IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_001a: brfalse.s IL_0029 + IL_001c: ldloc.0 + IL_001d: ldstr ""Literal"" + IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)"" + IL_0027: br.s IL_002a + IL_0029: ldc.i4.0 + IL_002a: pop + IL_002b: ldloc.0 + IL_002c: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void LambdaReturnInference_01(string expression) + { + var code = @" +using System; +Func f = () => " + expression + @"; +Console.WriteLine(f()); +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL(@"Program.<>c.<
$>b__0_0()", @" +{ + // Code size 45 (0x2d) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldc.i4.1 + IL_000a: box ""int"" + IL_000f: ldc.i4.2 + IL_0010: ldstr ""f"" + IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_001a: brfalse.s IL_0029 + IL_001c: ldloc.0 + IL_001d: ldstr ""Literal"" + IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)"" + IL_0027: br.s IL_002a + IL_0029: ldc.i4.0 + IL_002a: pop + IL_002b: ldloc.0 + IL_002c: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void LambdaReturnInference_02(string expression) + { + var code = @" +using System; +CultureInfoNormalizer.Normalize(); +C.M(() => " + expression + @"); + +class C +{ + public static void M(Func f) => Console.WriteLine(f()); + public static void M(Func f) => throw null; +} +"; + + // Interpolated string handler conversions are not considered when determining the natural type of an expression: the natural return type of this lambda is string, + // so we don't even consider that there is a conversion from interpolated string expression to CustomHandler here (Sections 12.6.3.13 and 12.6.3.15 of the spec). + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }); + var verifier = CompileAndVerify(comp, expectedOutput: @"1.00Literal"); + + // No DefaultInterpolatedStringHandler was included in the compilation, so it falls back to string.Format + verifier.VerifyIL(@"Program.<>c.<
$>b__0_0()", !expression.Contains('+') ? @" +{ + // Code size 17 (0x11) + .maxstack 2 + IL_0000: ldstr ""{0,2:f}Literal"" + IL_0005: ldc.i4.1 + IL_0006: box ""int"" + IL_000b: call ""string string.Format(string, object)"" + IL_0010: ret +} +" +: @" +{ + // Code size 27 (0x1b) + .maxstack 2 + IL_0000: ldstr ""{0,2:f}"" + IL_0005: ldc.i4.1 + IL_0006: box ""int"" + IL_000b: call ""string string.Format(string, object)"" + IL_0010: ldstr ""Literal"" + IL_0015: call ""string string.Concat(string, string)"" + IL_001a: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{new S { Field = """"""Field"""""" }}""""""")] + [InlineData(@"$""""""{new S { Field = """"""Field"""""" }}"""""" + $"""""" + +""""""")] + public void LambdaReturnInference_03(string expression) + { + // Same as 2, but using a type that isn't allowed in an interpolated string. There is an implicit conversion error on the ref struct + // when converting to a string, because S cannot be a component of an interpolated string. This conversion error causes the lambda to + // fail to bind as Func, even though the natural return type is string, and the only successful bind is Func. + + var code = @" +using System; +C.M(() => " + expression + @"); + +static class C +{ + public static void M(Func f) => throw null; + public static void M(Func f) => Console.WriteLine(f()); +} + +public partial class CustomHandler +{ + public void AppendFormatted(S value) => _builder.AppendLine(""value:"" + value.Field); +} +public ref struct S +{ + public string Field { get; set; } +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"value:Field"); + + verifier.VerifyIL(@"Program.<>c.<
$>b__0_0()", @" +{ + // Code size 35 (0x23) + .maxstack 4 + .locals init (S V_0) + IL_0000: ldc.i4.0 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: dup + IL_0008: ldloca.s V_0 + IL_000a: initobj ""S"" + IL_0010: ldloca.s V_0 + IL_0012: ldstr ""Field"" + IL_0017: call ""void S.Field.set"" + IL_001c: ldloc.0 + IL_001d: callvirt ""void CustomHandler.AppendFormatted(S)"" + IL_0022: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{new S { Field = """"""Field"""""" }}""""""")] + [InlineData(@"$""""""{new S { Field = """"""Field"""""" }}"""""" + $"""""" + +""""""")] + public void LambdaReturnInference_04(string expression) + { + // Same as 3, but with S added to DefaultInterpolatedStringHandler (which then allows the lambda to be bound as Func, matching the natural return type) + + var code = @" +using System; +C.M(() => " + expression + @"); + +static class C +{ + public static void M(Func f) => Console.WriteLine(f()); + public static void M(Func f) => throw null; +} + +public partial class CustomHandler +{ + public void AppendFormatted(S value) => throw null; +} +public ref struct S +{ + public string Field { get; set; } +} +namespace System.Runtime.CompilerServices +{ + public ref partial struct DefaultInterpolatedStringHandler + { + public void AppendFormatted(S value) => _builder.AppendLine(""value:"" + value.Field); + } +} +"; + + string[] source = new[] { + code, + GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: false), + GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: true, useBoolReturns: false) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.NetCoreApp); + + 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. + // 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. + // 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. + // C.M(() => $"""{new S { Field = """Field""" }}""" + $""" + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$"""""" + +""""""").WithArguments("raw string literals").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. + // 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. + // C.M(() => $"""{new S { Field = """Field""" }}"""); + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""Field""""""").WithArguments("raw string literals").WithLocation(3, 32)); + } + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.NetCoreApp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"value:Field"); + + verifier.VerifyIL(@"Program.<>c.<
$>b__0_0()", @" +{ + // Code size 45 (0x2d) + .maxstack 3 + .locals init (System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_0, + S V_1) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.0 + IL_0003: ldc.i4.1 + IL_0004: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0009: ldloca.s V_0 + IL_000b: ldloca.s V_1 + IL_000d: initobj ""S"" + IL_0013: ldloca.s V_1 + IL_0015: ldstr ""Field"" + IL_001a: call ""void S.Field.set"" + IL_001f: ldloc.1 + IL_0020: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(S)"" + IL_0025: ldloca.s V_0 + IL_0027: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_002c: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void LambdaReturnInference_05(string expression) + { + var code = @" +using System; +C.M(b => + { + if (b) return default(CustomHandler); + else return " + expression + @"; + }); + +static class C +{ + public static void M(Func f) => throw null; + public static void M(Func f) => Console.WriteLine(f(false)); +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL(@"Program.<>c.<
$>b__0_0(bool)", @" +{ + // Code size 55 (0x37) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldarg.1 + IL_0001: brfalse.s IL_000d + IL_0003: ldloca.s V_0 + IL_0005: initobj ""CustomHandler"" + IL_000b: ldloc.0 + IL_000c: ret + IL_000d: ldloca.s V_0 + IL_000f: ldc.i4.7 + IL_0010: ldc.i4.1 + IL_0011: call ""CustomHandler..ctor(int, int)"" + IL_0016: ldloca.s V_0 + IL_0018: ldc.i4.1 + IL_0019: box ""int"" + IL_001e: ldc.i4.2 + IL_001f: ldstr ""f"" + IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0029: ldloca.s V_0 + IL_002b: ldstr ""Literal"" + IL_0030: call ""void CustomHandler.AppendLiteral(string)"" + IL_0035: ldloc.0 + IL_0036: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void LambdaReturnInference_06(string expression) + { + // Same as 5, but with an implicit conversion from the builder type to string. This implicit conversion + // means that a best common type can be inferred for all branches of the lambda expression (Section 12.6.3.15 of the spec) + // and because there is a best common type, the inferred return type of the lambda is string. Since the inferred return type + // has an identity conversion to the return type of Func, that is preferred. + var code = @" +using System; +CultureInfoNormalizer.Normalize(); +C.M(b => + { + if (b) return default(CustomHandler); + else return " + expression + @"; + }); + +static class C +{ + public static void M(Func f) => Console.WriteLine(f(false)); + public static void M(Func f) => throw null; +} +public partial struct CustomHandler +{ + public static implicit operator string(CustomHandler c) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"1.00Literal"); + + verifier.VerifyIL(@"Program.<>c.<
$>b__0_0(bool)", !expression.Contains('+') ? @" +{ + // Code size 35 (0x23) + .maxstack 2 + .locals init (CustomHandler V_0) + IL_0000: ldarg.1 + IL_0001: brfalse.s IL_0012 + IL_0003: ldloca.s V_0 + IL_0005: initobj ""CustomHandler"" + IL_000b: ldloc.0 + IL_000c: call ""string CustomHandler.op_Implicit(CustomHandler)"" + IL_0011: ret + IL_0012: ldstr ""{0,2:f}Literal"" + IL_0017: ldc.i4.1 + IL_0018: box ""int"" + IL_001d: call ""string string.Format(string, object)"" + IL_0022: ret +} +" +: @" +{ + // Code size 45 (0x2d) + .maxstack 2 + .locals init (CustomHandler V_0) + IL_0000: ldarg.1 + IL_0001: brfalse.s IL_0012 + IL_0003: ldloca.s V_0 + IL_0005: initobj ""CustomHandler"" + IL_000b: ldloc.0 + IL_000c: call ""string CustomHandler.op_Implicit(CustomHandler)"" + IL_0011: ret + IL_0012: ldstr ""{0,2:f}"" + IL_0017: ldc.i4.1 + IL_0018: box ""int"" + IL_001d: call ""string string.Format(string, object)"" + IL_0022: ldstr ""Literal"" + IL_0027: call ""string string.Concat(string, string)"" + IL_002c: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void LambdaReturnInference_07(string expression) + { + // Same as 5, but with an implicit conversion from string to the builder type. + var code = @" +using System; +C.M(b => + { + if (b) return default(CustomHandler); + else return " + expression + @"; + }); + +static class C +{ + public static void M(Func f) => Console.WriteLine(f(false)); + public static void M(Func f) => Console.WriteLine(f(false)); +} +public partial struct CustomHandler +{ + public static implicit operator CustomHandler(string s) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL(@"Program.<>c.<
$>b__0_0(bool)", @" +{ + // Code size 55 (0x37) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldarg.1 + IL_0001: brfalse.s IL_000d + IL_0003: ldloca.s V_0 + IL_0005: initobj ""CustomHandler"" + IL_000b: ldloc.0 + IL_000c: ret + IL_000d: ldloca.s V_0 + IL_000f: ldc.i4.7 + IL_0010: ldc.i4.1 + IL_0011: call ""CustomHandler..ctor(int, int)"" + IL_0016: ldloca.s V_0 + IL_0018: ldc.i4.1 + IL_0019: box ""int"" + IL_001e: ldc.i4.2 + IL_001f: ldstr ""f"" + IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0029: ldloca.s V_0 + IL_002b: ldstr ""Literal"" + IL_0030: call ""void CustomHandler.AppendLiteral(string)"" + IL_0035: ldloc.0 + IL_0036: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void LambdaReturnInference_08(string expression) + { + // Same as 5, but with an implicit conversion from the builder type to string and from string to the builder type. + var code = @" +using System; +C.M(b => + { + if (b) return default(CustomHandler); + else return " + expression + @"; + }); + +static class C +{ + public static void M(Func f) => Console.WriteLine(f(false)); + public static void M(Func f) => throw null; +} +public partial struct CustomHandler +{ + public static implicit operator string(CustomHandler c) => throw null; + public static implicit operator CustomHandler(string c) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (3,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(Func)' and 'C.M(Func)' + // C.M(b => + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(System.Func)", "C.M(System.Func)").WithLocation(3, 3)); + } + + [Theory] + [InlineData(@"$""""""{1}""""""")] + [InlineData(@"$""""""{1}"""""" + $""""""{2}""""""")] + public void LambdaInference_AmbiguousInOlderLangVersions(string expression) + { + var code = @" +using System; +C.M(param => + { + param = " + expression + @"; + }); + +static class C +{ + public static void M(Action f) => throw null; + public static void M(Action f) => throw null; +} +"; + + var source = new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + + 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. + // 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. + // param = $"""{1}""" + $"""{2}"""; + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{2}""""""").WithArguments("raw string literals").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. + // param = $"""{1}"""; + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"$""""""{1}""""""").WithArguments("raw string literals").WithLocation(5, 17)); + } + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + + if (expression.Contains('+')) + { + comp.VerifyDiagnostics( + // (3,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(Action)' and 'C.M(Action)' + // C.M(param => + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(System.Action)", "C.M(System.Action)").WithLocation(3, 3)); + } + else + { + comp.VerifyDiagnostics( + // (3,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(Action)' and 'C.M(Action)' + // C.M(param => + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(System.Action)", "C.M(System.Action)").WithLocation(3, 3)); + } + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void TernaryTypes_01(string expression) + { + var code = @" +using System; + +var x = (bool)(object)false ? default(CustomHandler) : " + expression + @"; +Console.WriteLine(x); +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 76 (0x4c) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.0 + IL_0001: box ""bool"" + IL_0006: unbox.any ""bool"" + IL_000b: brtrue.s IL_0038 + IL_000d: ldloca.s V_0 + IL_000f: ldc.i4.7 + IL_0010: ldc.i4.1 + IL_0011: call ""CustomHandler..ctor(int, int)"" + IL_0016: ldloca.s V_0 + IL_0018: ldc.i4.1 + IL_0019: box ""int"" + IL_001e: ldc.i4.2 + IL_001f: ldstr ""f"" + IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0029: ldloca.s V_0 + IL_002b: ldstr ""Literal"" + IL_0030: call ""void CustomHandler.AppendLiteral(string)"" + IL_0035: ldloc.0 + IL_0036: br.s IL_0041 + IL_0038: ldloca.s V_0 + IL_003a: initobj ""CustomHandler"" + IL_0040: ldloc.0 + IL_0041: box ""CustomHandler"" + IL_0046: call ""void System.Console.WriteLine(object)"" + IL_004b: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void TernaryTypes_02(string expression) + { + // Same as 01, but with a conversion from CustomHandler to string. The rules here are similar to LambdaReturnInference_06 + var code = @" +using System; + +CultureInfoNormalizer.Normalize(); +var x = (bool)(object)false ? default(CustomHandler) : " + expression + @"; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator string(CustomHandler c) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"1.00Literal"); + + verifier.VerifyIL("", !expression.Contains('+') ? @" +{ + // Code size 56 (0x38) + .maxstack 2 + .locals init (CustomHandler V_0) + IL_0000: call ""void CultureInfoNormalizer.Normalize()"" + IL_0005: ldc.i4.0 + IL_0006: box ""bool"" + IL_000b: unbox.any ""bool"" + IL_0010: brtrue.s IL_0024 + IL_0012: ldstr ""{0,2:f}Literal"" + IL_0017: ldc.i4.1 + IL_0018: box ""int"" + IL_001d: call ""string string.Format(string, object)"" + IL_0022: br.s IL_0032 + IL_0024: ldloca.s V_0 + IL_0026: initobj ""CustomHandler"" + IL_002c: ldloc.0 + IL_002d: call ""string CustomHandler.op_Implicit(CustomHandler)"" + IL_0032: call ""void System.Console.WriteLine(string)"" + IL_0037: ret +} +" +: @" +{ + // Code size 66 (0x42) + .maxstack 2 + .locals init (CustomHandler V_0) + IL_0000: call ""void CultureInfoNormalizer.Normalize()"" + IL_0005: ldc.i4.0 + IL_0006: box ""bool"" + IL_000b: unbox.any ""bool"" + IL_0010: brtrue.s IL_002e + IL_0012: ldstr ""{0,2:f}"" + IL_0017: ldc.i4.1 + IL_0018: box ""int"" + IL_001d: call ""string string.Format(string, object)"" + IL_0022: ldstr ""Literal"" + IL_0027: call ""string string.Concat(string, string)"" + IL_002c: br.s IL_003c + IL_002e: ldloca.s V_0 + IL_0030: initobj ""CustomHandler"" + IL_0036: ldloc.0 + IL_0037: call ""string CustomHandler.op_Implicit(CustomHandler)"" + IL_003c: call ""void System.Console.WriteLine(string)"" + IL_0041: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void TernaryTypes_03(string expression) + { + // Same as 02, but with a target-type + var code = @" +using System; + +CustomHandler x = (bool)(object)false ? default(CustomHandler) : " + expression + @"; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator string(CustomHandler c) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (4,19): error CS0029: Cannot implicitly convert type 'string' to 'CustomHandler' + // CustomHandler x = (bool)(object)false ? default(CustomHandler) : $"{1,2:f}Literal"; + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"(bool)(object)false ? default(CustomHandler) : " + expression).WithArguments("string", "CustomHandler").WithLocation(4, 19)); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void TernaryTypes_04(string expression) + { + // Same 01, but with a conversion from string to CustomHandler. The rules here are similar to LambdaReturnInference_07 + var code = @" +using System; + +var x = (bool)(object)false ? default(CustomHandler) : " + expression + @"; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator CustomHandler(string c) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 76 (0x4c) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.0 + IL_0001: box ""bool"" + IL_0006: unbox.any ""bool"" + IL_000b: brtrue.s IL_0038 + IL_000d: ldloca.s V_0 + IL_000f: ldc.i4.7 + IL_0010: ldc.i4.1 + IL_0011: call ""CustomHandler..ctor(int, int)"" + IL_0016: ldloca.s V_0 + IL_0018: ldc.i4.1 + IL_0019: box ""int"" + IL_001e: ldc.i4.2 + IL_001f: ldstr ""f"" + IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0029: ldloca.s V_0 + IL_002b: ldstr ""Literal"" + IL_0030: call ""void CustomHandler.AppendLiteral(string)"" + IL_0035: ldloc.0 + IL_0036: br.s IL_0041 + IL_0038: ldloca.s V_0 + IL_003a: initobj ""CustomHandler"" + IL_0040: ldloc.0 + IL_0041: box ""CustomHandler"" + IL_0046: call ""void System.Console.WriteLine(object)"" + IL_004b: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void TernaryTypes_05(string expression) + { + // Same 01, but with a conversion from string to CustomHandler and CustomHandler to string. + var code = @" +using System; + +var x = (bool)(object)false ? default(CustomHandler) : " + expression + @"; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator CustomHandler(string c) => throw null; + public static implicit operator string(CustomHandler c) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (4,9): error CS0172: Type of conditional expression cannot be determined because 'CustomHandler' and 'string' implicitly convert to one another + // var x = (bool)(object)false ? default(CustomHandler) : $"{1,2:f}Literal"; + Diagnostic(ErrorCode.ERR_AmbigQM, @"(bool)(object)false ? default(CustomHandler) : " + expression).WithArguments("CustomHandler", "string").WithLocation(4, 9)); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void TernaryTypes_06(string expression) + { + // Same 05, but with a target type + var code = @" +using System; + +CustomHandler x = (bool)(object)false ? default(CustomHandler) : " + expression + @"; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator CustomHandler(string c) => throw null; + public static implicit operator string(CustomHandler c) => c.ToString(); +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 76 (0x4c) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.0 + IL_0001: box ""bool"" + IL_0006: unbox.any ""bool"" + IL_000b: brtrue.s IL_0038 + IL_000d: ldloca.s V_0 + IL_000f: ldc.i4.7 + IL_0010: ldc.i4.1 + IL_0011: call ""CustomHandler..ctor(int, int)"" + IL_0016: ldloca.s V_0 + IL_0018: ldc.i4.1 + IL_0019: box ""int"" + IL_001e: ldc.i4.2 + IL_001f: ldstr ""f"" + IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0029: ldloca.s V_0 + IL_002b: ldstr ""Literal"" + IL_0030: call ""void CustomHandler.AppendLiteral(string)"" + IL_0035: ldloc.0 + IL_0036: br.s IL_0041 + IL_0038: ldloca.s V_0 + IL_003a: initobj ""CustomHandler"" + IL_0040: ldloc.0 + IL_0041: call ""string CustomHandler.op_Implicit(CustomHandler)"" + IL_0046: call ""void System.Console.WriteLine(string)"" + IL_004b: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void SwitchTypes_01(string expression) + { + // Switch expressions infer a best type based on _types_, not based on expressions (section 12.6.3.15 of the spec). Because this is based on types + // and not on expression conversions, no best type can be found for this switch expression. + + var code = @" +using System; + +var x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" }; +Console.WriteLine(x); +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (4,29): error CS8506: No best type was found for the switch expression. + // var x = (bool)(object)false switch { true => default(CustomHandler), false => $"{1,2:f}Literal" }; + Diagnostic(ErrorCode.ERR_SwitchExpressionNoBestType, "switch").WithLocation(4, 29)); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void SwitchTypes_02(string expression) + { + // Same as 01, but with a conversion from CustomHandler. This allows the switch expression to infer a best-common type, which is string. + var code = @" +using System; + +CultureInfoNormalizer.Normalize(); +var x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" }; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator string(CustomHandler c) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"1.00Literal"); + + verifier.VerifyIL("", !expression.Contains('+') ? @" +{ + // Code size 59 (0x3b) + .maxstack 2 + .locals init (string V_0, + CustomHandler V_1) + IL_0000: call ""void CultureInfoNormalizer.Normalize()"" + IL_0005: ldc.i4.0 + IL_0006: box ""bool"" + IL_000b: unbox.any ""bool"" + IL_0010: brfalse.s IL_0023 + IL_0012: ldloca.s V_1 + IL_0014: initobj ""CustomHandler"" + IL_001a: ldloc.1 + IL_001b: call ""string CustomHandler.op_Implicit(CustomHandler)"" + IL_0020: stloc.0 + IL_0021: br.s IL_0034 + IL_0023: ldstr ""{0,2:f}Literal"" + IL_0028: ldc.i4.1 + IL_0029: box ""int"" + IL_002e: call ""string string.Format(string, object)"" + IL_0033: stloc.0 + IL_0034: ldloc.0 + IL_0035: call ""void System.Console.WriteLine(string)"" + IL_003a: ret +} +" +: @" +{ + // Code size 69 (0x45) + .maxstack 2 + .locals init (string V_0, + CustomHandler V_1) + IL_0000: call ""void CultureInfoNormalizer.Normalize()"" + IL_0005: ldc.i4.0 + IL_0006: box ""bool"" + IL_000b: unbox.any ""bool"" + IL_0010: brfalse.s IL_0023 + IL_0012: ldloca.s V_1 + IL_0014: initobj ""CustomHandler"" + IL_001a: ldloc.1 + IL_001b: call ""string CustomHandler.op_Implicit(CustomHandler)"" + IL_0020: stloc.0 + IL_0021: br.s IL_003e + IL_0023: ldstr ""{0,2:f}"" + IL_0028: ldc.i4.1 + IL_0029: box ""int"" + IL_002e: call ""string string.Format(string, object)"" + IL_0033: ldstr ""Literal"" + IL_0038: call ""string string.Concat(string, string)"" + IL_003d: stloc.0 + IL_003e: ldloc.0 + IL_003f: call ""void System.Console.WriteLine(string)"" + IL_0044: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void SwitchTypes_03(string expression) + { + // Same 02, but with a target-type. The natural type will fail to compile, so the switch will use a target type (unlike TernaryTypes_03, which fails to compile). + var code = @" +using System; + +CustomHandler x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" }; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator string(CustomHandler c) => c.ToString(); +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 79 (0x4f) + .maxstack 4 + .locals init (CustomHandler V_0, + CustomHandler V_1) + IL_0000: ldc.i4.0 + IL_0001: box ""bool"" + IL_0006: unbox.any ""bool"" + IL_000b: brfalse.s IL_0019 + IL_000d: ldloca.s V_1 + IL_000f: initobj ""CustomHandler"" + IL_0015: ldloc.1 + IL_0016: stloc.0 + IL_0017: br.s IL_0043 + IL_0019: ldloca.s V_1 + IL_001b: ldc.i4.7 + IL_001c: ldc.i4.1 + IL_001d: call ""CustomHandler..ctor(int, int)"" + IL_0022: ldloca.s V_1 + IL_0024: ldc.i4.1 + IL_0025: box ""int"" + IL_002a: ldc.i4.2 + IL_002b: ldstr ""f"" + IL_0030: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0035: ldloca.s V_1 + IL_0037: ldstr ""Literal"" + IL_003c: call ""void CustomHandler.AppendLiteral(string)"" + IL_0041: ldloc.1 + IL_0042: stloc.0 + IL_0043: ldloc.0 + IL_0044: call ""string CustomHandler.op_Implicit(CustomHandler)"" + IL_0049: call ""void System.Console.WriteLine(string)"" + IL_004e: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void SwitchTypes_04(string expression) + { + // Same as 01, but with a conversion to CustomHandler. This allows the switch expression to infer a best-common type, which is CustomHandler. + var code = @" +using System; + +var x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" }; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator CustomHandler(string c) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 79 (0x4f) + .maxstack 4 + .locals init (CustomHandler V_0, + CustomHandler V_1) + IL_0000: ldc.i4.0 + IL_0001: box ""bool"" + IL_0006: unbox.any ""bool"" + IL_000b: brfalse.s IL_0019 + IL_000d: ldloca.s V_1 + IL_000f: initobj ""CustomHandler"" + IL_0015: ldloc.1 + IL_0016: stloc.0 + IL_0017: br.s IL_0043 + IL_0019: ldloca.s V_1 + IL_001b: ldc.i4.7 + IL_001c: ldc.i4.1 + IL_001d: call ""CustomHandler..ctor(int, int)"" + IL_0022: ldloca.s V_1 + IL_0024: ldc.i4.1 + IL_0025: box ""int"" + IL_002a: ldc.i4.2 + IL_002b: ldstr ""f"" + IL_0030: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0035: ldloca.s V_1 + IL_0037: ldstr ""Literal"" + IL_003c: call ""void CustomHandler.AppendLiteral(string)"" + IL_0041: ldloc.1 + IL_0042: stloc.0 + IL_0043: ldloc.0 + IL_0044: box ""CustomHandler"" + IL_0049: call ""void System.Console.WriteLine(object)"" + IL_004e: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void SwitchTypes_05(string expression) + { + // Same as 01, but with conversions in both directions. No best common type can be found. + var code = @" +using System; + +var x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" }; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator CustomHandler(string c) => throw null; + public static implicit operator string(CustomHandler c) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (4,29): error CS8506: No best type was found for the switch expression. + // var x = (bool)(object)false switch { true => default(CustomHandler), false => $"{1,2:f}Literal" }; + Diagnostic(ErrorCode.ERR_SwitchExpressionNoBestType, "switch").WithLocation(4, 29)); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void SwitchTypes_06(string expression) + { + // Same as 05, but with a target type. + var code = @" +using System; + +CustomHandler x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" }; +Console.WriteLine(x); + +public partial struct CustomHandler +{ + public static implicit operator CustomHandler(string c) => throw null; + public static implicit operator string(CustomHandler c) => c.ToString(); +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 79 (0x4f) + .maxstack 4 + .locals init (CustomHandler V_0, + CustomHandler V_1) + IL_0000: ldc.i4.0 + IL_0001: box ""bool"" + IL_0006: unbox.any ""bool"" + IL_000b: brfalse.s IL_0019 + IL_000d: ldloca.s V_1 + IL_000f: initobj ""CustomHandler"" + IL_0015: ldloc.1 + IL_0016: stloc.0 + IL_0017: br.s IL_0043 + IL_0019: ldloca.s V_1 + IL_001b: ldc.i4.7 + IL_001c: ldc.i4.1 + IL_001d: call ""CustomHandler..ctor(int, int)"" + IL_0022: ldloca.s V_1 + IL_0024: ldc.i4.1 + IL_0025: box ""int"" + IL_002a: ldc.i4.2 + IL_002b: ldstr ""f"" + IL_0030: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0035: ldloca.s V_1 + IL_0037: ldstr ""Literal"" + IL_003c: call ""void CustomHandler.AppendLiteral(string)"" + IL_0041: ldloc.1 + IL_0042: stloc.0 + IL_0043: ldloc.0 + IL_0044: call ""string CustomHandler.op_Implicit(CustomHandler)"" + IL_0049: call ""void System.Console.WriteLine(string)"" + IL_004e: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void PassAsRefWithoutKeyword_01(string expression) + { + var code = @" +M(" + expression + @"); + +void M(ref CustomHandler c) => System.Console.WriteLine(c);"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 48 (0x30) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.7 + IL_0003: ldc.i4.1 + IL_0004: call ""CustomHandler..ctor(int, int)"" + IL_0009: ldloca.s V_0 + IL_000b: ldc.i4.1 + IL_000c: box ""int"" + IL_0011: ldc.i4.2 + IL_0012: ldstr ""f"" + IL_0017: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_001c: ldloca.s V_0 + IL_001e: ldstr ""Literal"" + IL_0023: call ""void CustomHandler.AppendLiteral(string)"" + IL_0028: ldloca.s V_0 + IL_002a: call ""void Program.<
$>g__M|0_0(ref CustomHandler)"" + IL_002f: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void PassAsRefWithoutKeyword_02(string expression) + { + var code = @" +M(" + expression + @"); +M(ref " + expression + @"); + +void M(ref CustomHandler c) => System.Console.WriteLine(c);"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (2,3): error CS1620: Argument 1 must be passed with the 'ref' keyword + // M($"{1,2:f}Literal"); + Diagnostic(ErrorCode.ERR_BadArgRef, expression).WithArguments("1", "ref").WithLocation(2, 3), + // (3,7): error CS1510: A ref or out value must be an assignable variable + // M(ref $"{1,2:f}Literal"); + Diagnostic(ErrorCode.ERR_RefLvalueExpected, expression).WithLocation(3, 7)); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void PassAsRefWithoutKeyword_03(string expression) + { + var code = @" +M(" + expression + @"); + +void M(in CustomHandler c) => System.Console.WriteLine(c);"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 45 (0x2d) + .maxstack 5 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.1 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: dup + IL_0008: ldc.i4.1 + IL_0009: box ""int"" + IL_000e: ldc.i4.2 + IL_000f: ldstr ""f"" + IL_0014: callvirt ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0019: dup + IL_001a: ldstr ""Literal"" + IL_001f: callvirt ""void CustomHandler.AppendLiteral(string)"" + IL_0024: stloc.0 + IL_0025: ldloca.s V_0 + IL_0027: call ""void Program.<
$>g__M|0_0(in CustomHandler)"" + IL_002c: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void PassAsRefWithoutKeyword_04(string expression) + { + var code = @" +M(" + expression + @"); + +void M(in CustomHandler c) => System.Console.WriteLine(c);"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 48 (0x30) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.7 + IL_0003: ldc.i4.1 + IL_0004: call ""CustomHandler..ctor(int, int)"" + IL_0009: ldloca.s V_0 + IL_000b: ldc.i4.1 + IL_000c: box ""int"" + IL_0011: ldc.i4.2 + IL_0012: ldstr ""f"" + IL_0017: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_001c: ldloca.s V_0 + IL_001e: ldstr ""Literal"" + IL_0023: call ""void CustomHandler.AppendLiteral(string)"" + IL_0028: ldloca.s V_0 + IL_002a: call ""void Program.<
$>g__M|0_0(in CustomHandler)"" + IL_002f: ret +} +"); + } + + [Theory] + [CombinatorialData] + public void RefOverloadResolution_Struct([CombinatorialValues("in", "ref")] string refKind, [CombinatorialValues(@"$""""""{1,2:f}Literal""""""", @"$""""""{1,2:f}"""""" + $""""""Literal""""""")] string expression) + { + var code = @" +C.M(" + expression + @"); + +class C +{ + public static void M(CustomHandler c) => System.Console.WriteLine(c); + public static void M(" + refKind + @" CustomHandler c) => throw null; +}"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 47 (0x2f) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.7 + IL_0003: ldc.i4.1 + IL_0004: call ""CustomHandler..ctor(int, int)"" + IL_0009: ldloca.s V_0 + IL_000b: ldc.i4.1 + IL_000c: box ""int"" + IL_0011: ldc.i4.2 + IL_0012: ldstr ""f"" + IL_0017: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_001c: ldloca.s V_0 + IL_001e: ldstr ""Literal"" + IL_0023: call ""void CustomHandler.AppendLiteral(string)"" + IL_0028: ldloc.0 + IL_0029: call ""void C.M(CustomHandler)"" + IL_002e: ret +} +"); + } + + [Theory] + [CombinatorialData] + public void RefOverloadResolution_Class([CombinatorialValues("in", "ref")] string refKind, [CombinatorialValues(@"$""""""{1,2:f}Literal""""""", @"$""""""{1,2:f}"""""" + $""""""Literal""""""")] string expression) + { + var code = @" +C.M(" + expression + @"); + +class C +{ + public static void M(CustomHandler c) => System.Console.WriteLine(c); + public static void M(" + refKind + @" CustomHandler c) => System.Console.WriteLine(c); +}"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp); + VerifyInterpolatedStringExpression(comp); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 47 (0x2f) + .maxstack 4 + .locals init (CustomHandler V_0) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.7 + IL_0003: ldc.i4.1 + IL_0004: call ""CustomHandler..ctor(int, int)"" + IL_0009: ldloca.s V_0 + IL_000b: ldc.i4.1 + IL_000c: box ""int"" + IL_0011: ldc.i4.2 + IL_0012: ldstr ""f"" + IL_0017: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_001c: ldloca.s V_0 + IL_001e: ldstr ""Literal"" + IL_0023: call ""void CustomHandler.AppendLiteral(string)"" + IL_0028: ldloc.0 + IL_0029: call ""void C.M(CustomHandler)"" + IL_002e: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1,2:f}Literal""""""")] + [InlineData(@"$""""""{1,2:f}"""""" + $""""""Literal""""""")] + public void RefOverloadResolution_MultipleBuilderTypes(string expression) + { + var code = @" +C.M(" + expression + @"); + +class C +{ + public static void M(CustomHandler1 c) => System.Console.WriteLine(c); + public static void M(ref CustomHandler2 c) => throw null; +}"; + + var comp = CreateCompilation(new[] + { + code, + GetInterpolatedStringCustomHandlerType("CustomHandler1", "struct", useBoolReturns: false), + GetInterpolatedStringCustomHandlerType("CustomHandler2", "struct", useBoolReturns: false, includeOneTimeHelpers: false) + }); + VerifyInterpolatedStringExpression(comp, "CustomHandler1"); + var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @" +value:1 +alignment:2 +format:f +literal:Literal"); + + verifier.VerifyIL("", @" +{ + // Code size 47 (0x2f) + .maxstack 4 + .locals init (CustomHandler1 V_0) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.7 + IL_0003: ldc.i4.1 + IL_0004: call ""CustomHandler1..ctor(int, int)"" + IL_0009: ldloca.s V_0 + IL_000b: ldc.i4.1 + IL_000c: box ""int"" + IL_0011: ldc.i4.2 + IL_0012: ldstr ""f"" + IL_0017: call ""void CustomHandler1.AppendFormatted(object, int, string)"" + IL_001c: ldloca.s V_0 + IL_001e: ldstr ""Literal"" + IL_0023: call ""void CustomHandler1.AppendLiteral(string)"" + IL_0028: ldloc.0 + IL_0029: call ""void C.M(CustomHandler1)"" + IL_002e: ret +} +"); + } + + private const string InterpolatedStringHandlerAttributesVB = @" +Namespace System.Runtime.CompilerServices + + Public NotInheritable Class InterpolatedStringHandlerAttribute + Inherits Attribute + End Class + + Public NotInheritable Class InterpolatedStringHandlerArgumentAttribute + Inherits Attribute + + Public Sub New(argument As String) + Arguments = { argument } + End Sub + + Public Sub New(ParamArray arguments() as String) + Me.Arguments = arguments + End Sub + + Public ReadOnly Property Arguments As String() + End Class +End Namespace +"; + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_NonHandlerType(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(" + expression + @"); + +class C +{ + public static void M([InterpolatedStringHandlerArgumentAttribute] string s) {} +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute }); + comp.VerifyDiagnostics( + // (8,27): error CS8946: 'string' is not an interpolated string handler type. + // public static void M([InterpolatedStringHandlerArgumentAttribute] string s) {} + Diagnostic(ErrorCode.ERR_TypeIsNotAnInterpolatedStringHandlerType, "InterpolatedStringHandlerArgumentAttribute").WithArguments("string").WithLocation(expression.Contains('+') ? 12 : 10, 27)); + + var sParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + sParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(sParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(sParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeError_NonHandlerType_Metadata() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M(i as Integer, c As String) + End Sub +End Class +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + // Note: there is no compilation error here because the natural type of a string is still string, and + // we just bind to that method without checking the handler attribute. + var comp = CreateCompilation(@"C.M(1, $"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics(); + + var sParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + sParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(sParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(sParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_InvalidArgument(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(" + expression + @"); + +class C +{ + public static void M([InterpolatedStringHandlerArgumentAttribute(1)] CustomHandler c) {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (8,70): error CS1503: Argument 1: cannot convert from 'int' to 'string' + // public static void M([InterpolatedStringHandlerArgumentAttribute(1)] CustomHandler c) {} + Diagnostic(ErrorCode.ERR_BadArgType, "1").WithArguments("1", "int", "string").WithLocation(expression.Contains('+') ? 12 : 10, 70)); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.False(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_01(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(" + expression + @"); + +class C +{ + public static void M([InterpolatedStringHandlerArgumentAttribute(""NonExistant"")] CustomHandler c) {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (4,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 5), + // (8,27): error CS8945: 'NonExistant' is not a valid parameter name from 'C.M(CustomHandler)'. + // public static void M([InterpolatedStringHandlerArgumentAttribute("NonExistant")] CustomHandler c) {} + Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute(""NonExistant"")").WithArguments("NonExistant", "C.M(CustomHandler)").WithLocation(expression.Contains('+') ? 12 : 10, 27)); + + var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_01_FromMetadata() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M( c As CustomHandler) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"C.M($"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 5), + // (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // C.M($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 5), + // (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 5)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_02(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(1, " + expression + @"); + +class C +{ + public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"", ""NonExistant"")] CustomHandler c) {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (4,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 8), + // (8,34): error CS8945: 'NonExistant' is not a valid parameter name from 'C.M(int, CustomHandler)'. + // public static void M(int i, [InterpolatedStringHandlerArgumentAttribute("i", "NonExistant")] CustomHandler c) {} + Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute(""i"", ""NonExistant"")").WithArguments("NonExistant", "C.M(int, CustomHandler)").WithLocation(expression.Contains('+') ? 12 : 10, 34)); + + var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_02_FromMetadata() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M(i As Integer, c As CustomHandler) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"C.M(1, $"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_03(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(1, " + expression + @"); + +class C +{ + public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""NonExistant1"", ""NonExistant2"")] CustomHandler c) {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (4,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 8), + // (8,34): error CS8945: 'NonExistant1' is not a valid parameter name from 'C.M(int, CustomHandler)'. + // public static void M(int i, [InterpolatedStringHandlerArgumentAttribute("NonExistant1", "NonExistant2")] CustomHandler c) {} + Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute(""NonExistant1"", ""NonExistant2"")").WithArguments("NonExistant1", "C.M(int, CustomHandler)").WithLocation(expression.Contains('+') ? 12 : 10, 34), + // (8,34): error CS8945: 'NonExistant2' is not a valid parameter name from 'C.M(int, CustomHandler)'. + // public static void M(int i, [InterpolatedStringHandlerArgumentAttribute("NonExistant1", "NonExistant2")] CustomHandler c) {} + Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute(""NonExistant1"", ""NonExistant2"")").WithArguments("NonExistant2", "C.M(int, CustomHandler)").WithLocation(expression.Contains('+') ? 12 : 10, 34)); + + var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_03_FromMetadata() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M(i As Integer, c As CustomHandler) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"C.M(1, $"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_ReferenceSelf(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(1, " + expression + @"); + +class C +{ + public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""c"")] CustomHandler c) {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (4,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 8), + // (8,34): error CS8948: InterpolatedStringHandlerArgumentAttribute arguments cannot refer to the parameter the attribute is used on. + // public static void M(int i, [InterpolatedStringHandlerArgumentAttribute("c")] CustomHandler c) {} + Diagnostic(ErrorCode.ERR_CannotUseSelfAsInterpolatedStringHandlerArgument, @"InterpolatedStringHandlerArgumentAttribute(""c"")").WithLocation(expression.Contains('+') ? 12 : 10, 34)); + + var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeError_ReferencesSelf_FromMetadata() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M( c As CustomHandler) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"C.M($"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 5), + // (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // C.M($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 5), + // (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 5)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_NullConstant(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(1, " + expression + @"); + +class C +{ + public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(new string[] { null })] CustomHandler c) {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (4,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 8), + // (8,34): error CS8943: null is not a valid parameter name. To get access to the receiver of an instance method, use the empty string as the parameter name. + // public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(new string[] { null })] CustomHandler c) {} + Diagnostic(ErrorCode.ERR_NullInvalidInterpolatedStringHandlerArgumentName, "InterpolatedStringHandlerArgumentAttribute(new string[] { null })").WithLocation(expression.Contains('+') ? 12 : 10, 34)); + + var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeError_NullConstant_FromMetadata_01() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M(i As Integer, c As CustomHandler) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"C.M(1, $"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeError_NullConstant_FromMetadata_02() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M(i As Integer, c As CustomHandler) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"C.M(1, $"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeError_NullConstant_FromMetadata_03() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M(i As Integer, c As CustomHandler) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"C.M(1, $"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_ThisOnStaticMethod(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(" + expression + @"); + +class C +{ + public static void M([InterpolatedStringHandlerArgumentAttribute("""")] CustomHandler c) {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (4,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 5), + // (8,27): error CS8944: 'C.M(CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument. + // public static void M([InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c) {} + Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute("""")").WithArguments("C.M(CustomHandler)").WithLocation(expression.Contains('+') ? 12 : 10, 27)); + + var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"{""""}")] + [InlineData(@"""""")] + public void InterpolatedStringHandlerArgumentAttributeError_ThisOnStaticMethod_FromMetadata(string arg) + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M( c As CustomHandler) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"C.M($"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 5), + // (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // C.M($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 5), + // (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 5)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_ThisOnConstructor(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +_ = new C(" + expression + @"); + +class C +{ + public C([InterpolatedStringHandlerArgumentAttribute("""")] CustomHandler c) {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (4,11): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // _ = new C($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 11), + // (8,15): error CS8944: 'C.C(CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument. + // public C([InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c) {} + Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute("""")").WithArguments("C.C(CustomHandler)").WithLocation(expression.Contains('+') ? 12 : 10, 15)); + + var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod(".ctor").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"{""""}")] + [InlineData(@"""""")] + public void InterpolatedStringHandlerArgumentAttributeError_ThisOnConstructor_FromMetadata(string arg) + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Sub New( c As CustomHandler) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"_ = new C($"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,11): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // _ = new C($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 11), + // (1,11): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // _ = new C($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 11), + // (1,11): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // _ = new C($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 11)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod(".ctor").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerAttributeArgumentError_SubstitutedTypeSymbol(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(" + expression + @"); + +public class C +{ + public static void M([InterpolatedStringHandlerArgumentAttribute] T t) { } +} +"; + + var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, customHandler }); + comp.VerifyDiagnostics( + // (4,20): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 20), + // (8,27): error CS8946: 'T' is not an interpolated string handler type. + // public static void M([InterpolatedStringHandlerArgumentAttribute] T t) { } + Diagnostic(ErrorCode.ERR_TypeIsNotAnInterpolatedStringHandlerType, "InterpolatedStringHandlerArgumentAttribute").WithArguments("T").WithLocation(expression.Contains('+') ? 12 : 10, 27)); + + var c = comp.SourceModule.GlobalNamespace.GetTypeMember("C"); + var handler = comp.SourceModule.GlobalNamespace.GetTypeMember("CustomHandler"); + + var substitutedC = c.WithTypeArguments(ImmutableArray.Create(TypeWithAnnotations.Create(handler))); + + var cParam = substitutedC.GetMethod("M").Parameters.Single(); + Assert.IsType(cParam); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeError_SubstitutedTypeSymbol_FromMetadata() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C(Of T) + Public Shared Sub M( c As T) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation(@"C.M($"""""" + +"""""");", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics( + // (1,20): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // C.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(1, 20), + // (1,20): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // C.M($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(1, 20), + // (1,20): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(1, 20)); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C`1").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + Assert.True(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Fact] + public void InterpolatedStringHandlerArgumentAttributeWarn_ParameterAfterHandler_FromMetadata() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Class C + Public Shared Sub M( c As CustomHandler, i As Integer) + End Sub +End Class + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var comp = CreateCompilation("", references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyEmitDiagnostics(); + + var customHandler = comp.GetTypeByMetadataName("CustomHandler"); + Assert.True(customHandler.IsInterpolatedStringHandlerType); + + var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.First(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(1, cParam.InterpolatedStringHandlerArgumentIndexes.Single()); + Assert.False(cParam.HasInterpolatedStringHandlerArgumentError); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_OptionalNotSpecifiedAtCallsite(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(" + expression + @"); + +public class C +{ + public static void M([InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c, int i = 0) { } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i) : this(literalLength, formattedCount) + { + } +} +"; + + var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, customHandler }); + comp.VerifyDiagnostics( + // (4,5): error CS8951: Parameter 'i' is not explicitly provided, but is used as an argument to the interpolated string handler conversion on parameter 'c'. Specify the value of 'i' before 'c'. + // C.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentOptionalNotSpecified, expression).WithArguments("i", "c").WithLocation(4, 5), + // (8,27): warning CS8947: Parameter 'i' occurs after 'c' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder + // parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. + // public static void M([InterpolatedStringHandlerArgumentAttribute("i")] CustomHandler c, int i = 0) { } + Diagnostic(ErrorCode.WRN_ParameterOccursAfterInterpolatedStringHandlerParameter, @"InterpolatedStringHandlerArgumentAttribute(""i"")").WithArguments("i", "c").WithLocation(expression.Contains('+') ? 12 : 10, 27)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttributeError_ParamsNotSpecifiedAtCallsite(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C.M(" + expression + @"); + +public class C +{ + public static void M([InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c, params int[] i) { } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int[] i) : this(literalLength, formattedCount) + { + } +} +"; + + var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, customHandler }); + comp.VerifyDiagnostics( + // (4,5): error CS8951: Parameter 'i' is not explicitly provided, but is used as an argument to the interpolated string handler conversion on parameter 'c'. Specify the value of 'i' before 'c'. + // C.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentOptionalNotSpecified, expression).WithArguments("i", "c").WithLocation(4, 5), + // (8,27): warning CS8947: Parameter 'i' occurs after 'c' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder + // parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved. + // public static void M([InterpolatedStringHandlerArgumentAttribute("i")] CustomHandler c, params int[] i) { } + Diagnostic(ErrorCode.WRN_ParameterOccursAfterInterpolatedStringHandlerParameter, @"InterpolatedStringHandlerArgumentAttribute(""i"")").WithArguments("i", "c").WithLocation(expression.Contains('+') ? 12 : 10, 27)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MissingConstructor(string expression) + { + var code = @" +using System.Runtime.CompilerServices; +public class C +{ + public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + // https://github.com/dotnet/roslyn/issues/53981 tracks warning here in the future, with user feedback. + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate).VerifyDiagnostics(); + + CreateCompilation(@"C.M(1, " + expression + @");", new[] { comp.ToMetadataReference() }).VerifyDiagnostics( + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, expression).WithArguments("CustomHandler", "3").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 4 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, expression).WithArguments("CustomHandler", "4").WithLocation(1, 8)); + + static void validate(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single()); + Assert.False(cParam.HasInterpolatedStringHandlerArgumentError); + } + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_InaccessibleConstructor_01(string expression) + { + var code = @" +using System.Runtime.CompilerServices; +public class C +{ + public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) {} +} + +public partial struct CustomHandler +{ + private CustomHandler(int literalLength, int formattedCount, int i) : this() {} + + static void InCustomHandler() + { + C.M(1, " + expression + @"); + } +} +"; + + var executableCode = @"C.M(1, " + expression + @");"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, executableCode, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (1,8): error CS0122: 'CustomHandler.CustomHandler(int, int, int)' is inaccessible due to its protection level + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadAccess, expression).WithArguments("CustomHandler.CustomHandler(int, int, int)").WithLocation(1, 8)); + + var dependency = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + + // https://github.com/dotnet/roslyn/issues/53981 tracks warning here in the future, with user feedback. + CompileAndVerify(dependency, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics(); + + comp = CreateCompilation(executableCode, new[] { dependency.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 4 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, expression).WithArguments("CustomHandler", "4").WithLocation(1, 8), + // (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, expression).WithArguments("CustomHandler", "3").WithLocation(1, 8)); + + comp = CreateCompilation(executableCode, new[] { dependency.ToMetadataReference() }); + comp.VerifyDiagnostics( + // (1,8): error CS0122: 'CustomHandler.CustomHandler(int, int, int)' is inaccessible due to its protection level + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadAccess, expression).WithArguments("CustomHandler.CustomHandler(int, int, int)").WithLocation(1, 8)); + + static void validate(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single()); + } + } + + private void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(string mRef, string customHandlerRef, string expression, params DiagnosticDescription[] expectedDiagnostics) + { + var code = @" +using System.Runtime.CompilerServices; + +int i = 0; +C.M(" + mRef + @" i, " + expression + @"); + +public class C +{ + public static void M(" + mRef + @" int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) { " + (mRef == "out" ? "i = 0;" : "") + @" } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, " + customHandlerRef + @" int i) : this() { " + (customHandlerRef == "out" ? "i = 0;" : "") + @" } +} +"; + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics(expectedDiagnostics); + + var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single()); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_RefNone(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("ref", "", expression, + // (5,9): error CS1615: Argument 3 may not be passed with the 'ref' keyword + // C.M(ref i, $""); + Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "ref").WithLocation(5, 9)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_RefOut(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("ref", "out", expression, + // (5,9): error CS1620: Argument 3 must be passed with the 'out' keyword + // C.M(ref i, $""); + Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "out").WithLocation(5, 9)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_RefIn(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("ref", "in", expression, + // (5,9): error CS1615: Argument 3 may not be passed with the 'ref' keyword + // C.M(ref i, $""); + Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "ref").WithLocation(5, 9)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_InNone(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("in", "", expression, + // (5,8): error CS1615: Argument 3 may not be passed with the 'in' keyword + // C.M(in i, $""); + Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "in").WithLocation(5, 8)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_InOut(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("in", "out", expression, + // (5,8): error CS1620: Argument 3 must be passed with the 'out' keyword + // C.M(in i, $""); + Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "out").WithLocation(5, 8)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_InRef(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("in", "ref", expression, + // (5,8): error CS1620: Argument 3 must be passed with the 'ref' keyword + // C.M(in i, $""); + Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(5, 8)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_OutNone(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("out", "", expression, + // (5,9): error CS1615: Argument 3 may not be passed with the 'out' keyword + // C.M(out i, $""); + Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "out").WithLocation(5, 9)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_OutRef(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("out", "ref", expression, + // (5,9): error CS1620: Argument 3 must be passed with the 'ref' keyword + // C.M(out i, $""); + Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(5, 9)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_NoneRef(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("", "ref", expression, + // (5,6): error CS1620: Argument 3 must be passed with the 'ref' keyword + // C.M( i, $""); + Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(5, 6)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_NoneOut(string expression) + { + InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes("", "out", expression, + // (5,6): error CS1620: Argument 3 must be passed with the 'out' keyword + // C.M( i, $""); + Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "out").WithLocation(5, 6)); + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_MismatchedType([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""", @"$"""""" + +"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System.Runtime.CompilerServices; +public class C +{ + public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) {} +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, string s" + extraConstructorArg + @") : this() + { +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var executableCode = @"C.M(1, " + expression + @");"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var expectedDiagnostics = extraConstructorArg == "" + ? new DiagnosticDescription[] + { + // (1,5): error CS1503: Argument 3: cannot convert from 'int' to 'string' + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadArgType, "1").WithArguments("3", "int", "string").WithLocation(1, 5) + } + : new DiagnosticDescription[] + { + // (1,5): error CS1503: Argument 3: cannot convert from 'int' to 'string' + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_BadArgType, "1").WithArguments("3", "int", "string").WithLocation(1, 5), + // (1,8): error CS7036: There is no argument given that corresponds to the required formal parameter 'success' of 'CustomHandler.CustomHandler(int, int, string, out bool)' + // C.M(1, $""); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("success", "CustomHandler.CustomHandler(int, int, string, out bool)").WithLocation(1, 8) + }; + + var comp = CreateCompilation(new[] { code, executableCode, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics(expectedDiagnostics); + + // https://github.com/dotnet/roslyn/issues/53981 tracks warning here in the future, with user feedback. + var dependency = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + CompileAndVerify(dependency, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics(); + + foreach (var d in new[] { dependency.EmitToImageReference(), dependency.ToMetadataReference() }) + { + comp = CreateCompilation(executableCode, new[] { d }); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + static void validate(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single()); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_SingleArg([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""2""""""", @"$""""""2"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +public class C +{ + public static string M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) => c.ToString(); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""i:"" + i.ToString()); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var executableCode = @" +using System; + +int i = 10; +Console.WriteLine(C.M(i, " + expression + @")); +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, executableCode, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @" +i:10 +literal:2"); + + verifier.VerifyDiagnostics(); + verifyIL(extraConstructorArg, verifier); + + var dependency = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + + foreach (var d in new[] { dependency.EmitToImageReference(), dependency.ToMetadataReference() }) + { + verifier = CompileAndVerify(executableCode, new[] { d }, expectedOutput: @" +i:10 +literal:2"); + verifier.VerifyDiagnostics(); + verifyIL(extraConstructorArg, verifier); + } + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single()); + } + + static void verifyIL(string extraConstructorArg, CompilationVerifier verifier) + { + verifier.VerifyIL("", extraConstructorArg == "" + ? @" +{ + // Code size 39 (0x27) + .maxstack 5 + .locals init (int V_0, + CustomHandler V_1) + IL_0000: ldc.i4.s 10 + IL_0002: stloc.0 + IL_0003: ldloc.0 + IL_0004: ldloca.s V_1 + IL_0006: ldc.i4.1 + IL_0007: ldc.i4.0 + IL_0008: ldloc.0 + IL_0009: call ""CustomHandler..ctor(int, int, int)"" + IL_000e: ldloca.s V_1 + IL_0010: ldstr ""2"" + IL_0015: call ""bool CustomHandler.AppendLiteral(string)"" + IL_001a: pop + IL_001b: ldloc.1 + IL_001c: call ""string C.M(int, CustomHandler)"" + IL_0021: call ""void System.Console.WriteLine(string)"" + IL_0026: ret +} +" +: @" +{ + // Code size 46 (0x2e) + .maxstack 5 + .locals init (int V_0, + CustomHandler V_1, + bool V_2) + IL_0000: ldc.i4.s 10 + IL_0002: stloc.0 + IL_0003: ldloc.0 + IL_0004: ldc.i4.1 + IL_0005: ldc.i4.0 + IL_0006: ldloc.0 + IL_0007: ldloca.s V_2 + IL_0009: newobj ""CustomHandler..ctor(int, int, int, out bool)"" + IL_000e: stloc.1 + IL_000f: ldloc.2 + IL_0010: brfalse.s IL_0020 + IL_0012: ldloca.s V_1 + IL_0014: ldstr ""2"" + IL_0019: call ""bool CustomHandler.AppendLiteral(string)"" + IL_001e: br.s IL_0021 + IL_0020: ldc.i4.0 + IL_0021: pop + IL_0022: ldloc.1 + IL_0023: call ""string C.M(int, CustomHandler)"" + IL_0028: call ""void System.Console.WriteLine(string)"" + IL_002d: ret +} +"); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_MultipleArgs([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; +public class C +{ + public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", ""s"")] CustomHandler c) => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i, string s" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""i:"" + i.ToString()); + _builder.AppendLine(""s:"" + s); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var executableCode = @" +int i = 10; +string s = ""arg""; +C.M(i, s, " + expression + @"); +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, executableCode, InterpolatedStringHandlerArgumentAttribute, handler }); + string expectedOutput = @" +i:10 +s:arg +literal:literal +"; + var verifier = base.CompileAndVerify((Compilation)comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: expectedOutput); + + verifier.VerifyDiagnostics(); + verifyIL(extraConstructorArg, verifier); + + var dependency = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + + foreach (var d in new[] { dependency.EmitToImageReference(), dependency.ToMetadataReference() }) + { + verifier = CompileAndVerify(executableCode, new[] { d }, expectedOutput: expectedOutput); + verifier.VerifyDiagnostics(); + verifyIL(extraConstructorArg, verifier); + } + + static void validator(ModuleSymbol verifier) + { + var cParam = verifier.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { 0, 1 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + + static void verifyIL(string extraConstructorArg, CompilationVerifier verifier) + { + verifier.VerifyIL("", (extraConstructorArg == "") + ? @" +{ + // Code size 44 (0x2c) + .maxstack 7 + .locals init (string V_0, //s + int V_1, + string V_2, + CustomHandler V_3) + IL_0000: ldc.i4.s 10 + IL_0002: ldstr ""arg"" + IL_0007: stloc.0 + IL_0008: stloc.1 + IL_0009: ldloc.1 + IL_000a: ldloc.0 + IL_000b: stloc.2 + IL_000c: ldloc.2 + IL_000d: ldloca.s V_3 + IL_000f: ldc.i4.7 + IL_0010: ldc.i4.0 + IL_0011: ldloc.1 + IL_0012: ldloc.2 + IL_0013: call ""CustomHandler..ctor(int, int, int, string)"" + IL_0018: ldloca.s V_3 + IL_001a: ldstr ""literal"" + IL_001f: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0024: pop + IL_0025: ldloc.3 + IL_0026: call ""void C.M(int, string, CustomHandler)"" + IL_002b: ret +} +" + : @" +{ + // Code size 52 (0x34) + .maxstack 7 + .locals init (string V_0, //s + int V_1, + string V_2, + CustomHandler V_3, + bool V_4) + IL_0000: ldc.i4.s 10 + IL_0002: ldstr ""arg"" + IL_0007: stloc.0 + IL_0008: stloc.1 + IL_0009: ldloc.1 + IL_000a: ldloc.0 + IL_000b: stloc.2 + IL_000c: ldloc.2 + IL_000d: ldc.i4.7 + IL_000e: ldc.i4.0 + IL_000f: ldloc.1 + IL_0010: ldloc.2 + IL_0011: ldloca.s V_4 + IL_0013: newobj ""CustomHandler..ctor(int, int, int, string, out bool)"" + IL_0018: stloc.3 + IL_0019: ldloc.s V_4 + IL_001b: brfalse.s IL_002b + IL_001d: ldloca.s V_3 + IL_001f: ldstr ""literal"" + IL_0024: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0029: br.s IL_002c + IL_002b: ldc.i4.0 + IL_002c: pop + IL_002d: ldloc.3 + IL_002e: call ""void C.M(int, string, CustomHandler)"" + IL_0033: ret +} +"); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_RefKindsMatch([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +int i = 1; +string s = null; +object o; +C.M(i, ref s, out o, " + expression + @"); +Console.WriteLine(s); +Console.WriteLine(o); + +public class C +{ + public static void M(in int i, ref string s, out object o, [InterpolatedStringHandlerArgumentAttribute(""i"", ""s"", ""o"")] CustomHandler c) + { + Console.WriteLine(s); + o = ""o in M""; + s = ""s in M""; + Console.Write(c.ToString()); + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, in int i, ref string s, out object o" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + o = null; + s = ""s in constructor""; + _builder.AppendLine(""i:"" + i.ToString()); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @" +s in constructor +i:1 +literal:literal +s in M +o in M +"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", (extraConstructorArg == "") + ? @" +{ + // Code size 67 (0x43) + .maxstack 8 + .locals init (int V_0, //i + string V_1, //s + object V_2, //o + int& V_3, + string& V_4, + object& V_5, + CustomHandler V_6) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldnull + IL_0003: stloc.1 + IL_0004: ldloca.s V_0 + IL_0006: stloc.3 + IL_0007: ldloc.3 + IL_0008: ldloca.s V_1 + IL_000a: stloc.s V_4 + IL_000c: ldloc.s V_4 + IL_000e: ldloca.s V_2 + IL_0010: stloc.s V_5 + IL_0012: ldloc.s V_5 + IL_0014: ldc.i4.7 + IL_0015: ldc.i4.0 + IL_0016: ldloc.3 + IL_0017: ldloc.s V_4 + IL_0019: ldloc.s V_5 + IL_001b: newobj ""CustomHandler..ctor(int, int, in int, ref string, out object)"" + IL_0020: stloc.s V_6 + IL_0022: ldloca.s V_6 + IL_0024: ldstr ""literal"" + IL_0029: call ""bool CustomHandler.AppendLiteral(string)"" + IL_002e: pop + IL_002f: ldloc.s V_6 + IL_0031: call ""void C.M(in int, ref string, out object, CustomHandler)"" + IL_0036: ldloc.1 + IL_0037: call ""void System.Console.WriteLine(string)"" + IL_003c: ldloc.2 + IL_003d: call ""void System.Console.WriteLine(object)"" + IL_0042: ret +} +" + : @" +{ + // Code size 76 (0x4c) + .maxstack 9 + .locals init (int V_0, //i + string V_1, //s + object V_2, //o + int& V_3, + string& V_4, + object& V_5, + CustomHandler V_6, + bool V_7) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldnull + IL_0003: stloc.1 + IL_0004: ldloca.s V_0 + IL_0006: stloc.3 + IL_0007: ldloc.3 + IL_0008: ldloca.s V_1 + IL_000a: stloc.s V_4 + IL_000c: ldloc.s V_4 + IL_000e: ldloca.s V_2 + IL_0010: stloc.s V_5 + IL_0012: ldloc.s V_5 + IL_0014: ldc.i4.7 + IL_0015: ldc.i4.0 + IL_0016: ldloc.3 + IL_0017: ldloc.s V_4 + IL_0019: ldloc.s V_5 + IL_001b: ldloca.s V_7 + IL_001d: newobj ""CustomHandler..ctor(int, int, in int, ref string, out object, out bool)"" + IL_0022: stloc.s V_6 + IL_0024: ldloc.s V_7 + IL_0026: brfalse.s IL_0036 + IL_0028: ldloca.s V_6 + IL_002a: ldstr ""literal"" + IL_002f: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0034: br.s IL_0037 + IL_0036: ldc.i4.0 + IL_0037: pop + IL_0038: ldloc.s V_6 + IL_003a: call ""void C.M(in int, ref string, out object, CustomHandler)"" + IL_003f: ldloc.1 + IL_0040: call ""void System.Console.WriteLine(string)"" + IL_0045: ldloc.2 + IL_0046: call ""void System.Console.WriteLine(object)"" + IL_004b: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(3).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { 0, 1, 2 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_ReorderedAttributePositions([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C.M(GetInt(), GetString(), " + expression + @"); + +int GetInt() +{ + Console.WriteLine(""GetInt""); + return 10; +} + +string GetString() +{ + Console.WriteLine(""GetString""); + return ""str""; +} + +public class C +{ + public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""s"", ""i"")] CustomHandler c) => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, string s, int i" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""s:"" + s); + _builder.AppendLine(""i:"" + i.ToString()); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @" +GetInt +GetString +s:str +i:10 +literal:literal +"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", (extraConstructorArg == "") + ? @" +{ + // Code size 45 (0x2d) + .maxstack 7 + .locals init (string V_0, + int V_1, + CustomHandler V_2) + IL_0000: call ""int Program.<
$>g__GetInt|0_0()"" + IL_0005: stloc.1 + IL_0006: ldloc.1 + IL_0007: call ""string Program.<
$>g__GetString|0_1()"" + IL_000c: stloc.0 + IL_000d: ldloc.0 + IL_000e: ldloca.s V_2 + IL_0010: ldc.i4.7 + IL_0011: ldc.i4.0 + IL_0012: ldloc.0 + IL_0013: ldloc.1 + IL_0014: call ""CustomHandler..ctor(int, int, string, int)"" + IL_0019: ldloca.s V_2 + IL_001b: ldstr ""literal"" + IL_0020: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0025: pop + IL_0026: ldloc.2 + IL_0027: call ""void C.M(int, string, CustomHandler)"" + IL_002c: ret +} +" + : @" +{ + // Code size 52 (0x34) + .maxstack 7 + .locals init (string V_0, + int V_1, + CustomHandler V_2, + bool V_3) + IL_0000: call ""int Program.<
$>g__GetInt|0_0()"" + IL_0005: stloc.1 + IL_0006: ldloc.1 + IL_0007: call ""string Program.<
$>g__GetString|0_1()"" + IL_000c: stloc.0 + IL_000d: ldloc.0 + IL_000e: ldc.i4.7 + IL_000f: ldc.i4.0 + IL_0010: ldloc.0 + IL_0011: ldloc.1 + IL_0012: ldloca.s V_3 + IL_0014: newobj ""CustomHandler..ctor(int, int, string, int, out bool)"" + IL_0019: stloc.2 + IL_001a: ldloc.3 + IL_001b: brfalse.s IL_002b + IL_001d: ldloca.s V_2 + IL_001f: ldstr ""literal"" + IL_0024: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0029: br.s IL_002c + IL_002b: ldc.i4.0 + IL_002c: pop + IL_002d: ldloc.2 + IL_002e: call ""void C.M(int, string, CustomHandler)"" + IL_0033: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { 1, 0 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_ParametersReordered([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +GetC().M(s: GetString(), i: GetInt(), c: " + expression + @"); + +C GetC() +{ + Console.WriteLine(""GetC""); + return new C { Field = 5 }; +} + +int GetInt() +{ + Console.WriteLine(""GetInt""); + return 10; +} + +string GetString() +{ + Console.WriteLine(""GetString""); + return ""str""; +} + +public class C +{ + public int Field; + public void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""s"", """", ""i"")] CustomHandler c) => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, string s, C c, int i" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""s:"" + s); + _builder.AppendLine(""c.Field:"" + c.Field.ToString()); + _builder.AppendLine(""i:"" + i.ToString()); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @" +GetC +GetString +GetInt +s:str +c.Field:5 +i:10 +literal:literal +"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", (extraConstructorArg == "") + ? @" +{ + // Code size 56 (0x38) + .maxstack 9 + .locals init (string V_0, + C V_1, + int V_2, + string V_3, + CustomHandler V_4) + IL_0000: call ""C Program.<
$>g__GetC|0_0()"" + IL_0005: stloc.1 + IL_0006: ldloc.1 + IL_0007: call ""string Program.<
$>g__GetString|0_2()"" + IL_000c: stloc.0 + IL_000d: ldloc.0 + IL_000e: stloc.3 + IL_000f: call ""int Program.<
$>g__GetInt|0_1()"" + IL_0014: stloc.2 + IL_0015: ldloc.2 + IL_0016: ldloc.3 + IL_0017: ldloca.s V_4 + IL_0019: ldc.i4.7 + IL_001a: ldc.i4.0 + IL_001b: ldloc.0 + IL_001c: ldloc.1 + IL_001d: ldloc.2 + IL_001e: call ""CustomHandler..ctor(int, int, string, C, int)"" + IL_0023: ldloca.s V_4 + IL_0025: ldstr ""literal"" + IL_002a: call ""bool CustomHandler.AppendLiteral(string)"" + IL_002f: pop + IL_0030: ldloc.s V_4 + IL_0032: callvirt ""void C.M(int, string, CustomHandler)"" + IL_0037: ret +} +" + : @" +{ + // Code size 65 (0x41) + .maxstack 9 + .locals init (string V_0, + C V_1, + int V_2, + string V_3, + CustomHandler V_4, + bool V_5) + IL_0000: call ""C Program.<
$>g__GetC|0_0()"" + IL_0005: stloc.1 + IL_0006: ldloc.1 + IL_0007: call ""string Program.<
$>g__GetString|0_2()"" + IL_000c: stloc.0 + IL_000d: ldloc.0 + IL_000e: stloc.3 + IL_000f: call ""int Program.<
$>g__GetInt|0_1()"" + IL_0014: stloc.2 + IL_0015: ldloc.2 + IL_0016: ldloc.3 + IL_0017: ldc.i4.7 + IL_0018: ldc.i4.0 + IL_0019: ldloc.0 + IL_001a: ldloc.1 + IL_001b: ldloc.2 + IL_001c: ldloca.s V_5 + IL_001e: newobj ""CustomHandler..ctor(int, int, string, C, int, out bool)"" + IL_0023: stloc.s V_4 + IL_0025: ldloc.s V_5 + IL_0027: brfalse.s IL_0037 + IL_0029: ldloca.s V_4 + IL_002b: ldstr ""literal"" + IL_0030: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0035: br.s IL_0038 + IL_0037: ldc.i4.0 + IL_0038: pop + IL_0039: ldloc.s V_4 + IL_003b: callvirt ""void C.M(int, string, CustomHandler)"" + IL_0040: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { 1, -1, 0 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_Duplicated([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C.M(GetInt(), """", " + expression + @"); + +int GetInt() +{ + Console.WriteLine(""GetInt""); + return 10; +} + +public class C +{ + public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", ""i"")] CustomHandler c) => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i1, int i2" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""i1:"" + i1.ToString()); + _builder.AppendLine(""i2:"" + i2.ToString()); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @" +GetInt +i1:10 +i2:10 +literal:literal +"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", (extraConstructorArg == "") + ? @" +{ + // Code size 43 (0x2b) + .maxstack 7 + .locals init (int V_0, + CustomHandler V_1) + IL_0000: call ""int Program.<
$>g__GetInt|0_0()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: ldstr """" + IL_000c: ldloca.s V_1 + IL_000e: ldc.i4.7 + IL_000f: ldc.i4.0 + IL_0010: ldloc.0 + IL_0011: ldloc.0 + IL_0012: call ""CustomHandler..ctor(int, int, int, int)"" + IL_0017: ldloca.s V_1 + IL_0019: ldstr ""literal"" + IL_001e: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0023: pop + IL_0024: ldloc.1 + IL_0025: call ""void C.M(int, string, CustomHandler)"" + IL_002a: ret +} +" + : @" +{ + // Code size 50 (0x32) + .maxstack 7 + .locals init (int V_0, + CustomHandler V_1, + bool V_2) + IL_0000: call ""int Program.<
$>g__GetInt|0_0()"" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: ldstr """" + IL_000c: ldc.i4.7 + IL_000d: ldc.i4.0 + IL_000e: ldloc.0 + IL_000f: ldloc.0 + IL_0010: ldloca.s V_2 + IL_0012: newobj ""CustomHandler..ctor(int, int, int, int, out bool)"" + IL_0017: stloc.1 + IL_0018: ldloc.2 + IL_0019: brfalse.s IL_0029 + IL_001b: ldloca.s V_1 + IL_001d: ldstr ""literal"" + IL_0022: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0027: br.s IL_002a + IL_0029: ldc.i4.0 + IL_002a: pop + IL_002b: ldloc.1 + IL_002c: call ""void C.M(int, string, CustomHandler)"" + IL_0031: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { 0, 0 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_EmptyWithMatchingConstructor([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""", @"$"""""" + +"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C.M(1, """", " + expression + @"); + +public class C +{ + public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute()] CustomHandler c) => Console.WriteLine(c.ToString()); +} +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount" + extraConstructorArg + @") + { +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: "CustomHandler").VerifyDiagnostics(); + + verifier.VerifyIL("", (extraConstructorArg == "") + ? @" +{ + // Code size 19 (0x13) + .maxstack 4 + IL_0000: ldc.i4.1 + IL_0001: ldstr """" + IL_0006: ldc.i4.0 + IL_0007: ldc.i4.0 + IL_0008: newobj ""CustomHandler..ctor(int, int)"" + IL_000d: call ""void C.M(int, string, CustomHandler)"" + IL_0012: ret +} +" + : @" +{ + // Code size 21 (0x15) + .maxstack 5 + .locals init (bool V_0) + IL_0000: ldc.i4.1 + IL_0001: ldstr """" + IL_0006: ldc.i4.0 + IL_0007: ldc.i4.0 + IL_0008: ldloca.s V_0 + IL_000a: newobj ""CustomHandler..ctor(int, int, out bool)"" + IL_000f: call ""void C.M(int, string, CustomHandler)"" + IL_0014: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_EmptyWithoutMatchingConstructor([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""", @"$"""""" + +"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System.Runtime.CompilerServices; +public class C +{ + public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute()] CustomHandler c) { } +} +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i" + extraConstructorArg + @") + { +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }); + // https://github.com/dotnet/roslyn/issues/53981 tracks warning here in the future, with user feedback. + CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics(); + + CreateCompilation(@"C.M(1, """", " + expression + @");", new[] { comp.EmitToImageReference() }).VerifyDiagnostics( + (extraConstructorArg == "") + ? new[] + { + // (1,12): error CS7036: There is no argument given that corresponds to the required formal parameter 'i' of 'CustomHandler.CustomHandler(int, int, int)' + // C.M(1, "", $""); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("i", "CustomHandler.CustomHandler(int, int, int)").WithLocation(1, 12), + // (1,12): error CS1615: Argument 3 may not be passed with the 'out' keyword + // C.M(1, "", $""); + Diagnostic(ErrorCode.ERR_BadArgExtraRef, expression).WithArguments("3", "out").WithLocation(1, 12) + } + : new[] + { + // (1,12): error CS7036: There is no argument given that corresponds to the required formal parameter 'i' of 'CustomHandler.CustomHandler(int, int, int, out bool)' + // C.M(1, "", $""); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("i", "CustomHandler.CustomHandler(int, int, int, out bool)").WithLocation(1, 12), + // (1,12): error CS7036: There is no argument given that corresponds to the required formal parameter 'success' of 'CustomHandler.CustomHandler(int, int, int, out bool)' + // C.M(1, "", $""); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("success", "CustomHandler.CustomHandler(int, int, int, out bool)").WithLocation(1, 12) + } + ); + + static void validate(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_OnIndexerRvalue([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +var c = new C(); +Console.WriteLine(c[10, ""str"", " + expression + @"]); + +public class C +{ + public string this[int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", ""s"")] CustomHandler c] { get => c.ToString(); } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i1, string s" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""i1:"" + i1.ToString()); + _builder.AppendLine(""s:"" + s); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @" +i1:10 +s:str +literal:literal +"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", (extraConstructorArg == "") + ? @" +{ + // Code size 52 (0x34) + .maxstack 8 + .locals init (int V_0, + string V_1, + CustomHandler V_2) + IL_0000: newobj ""C..ctor()"" + IL_0005: ldc.i4.s 10 + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldstr ""str"" + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: ldloca.s V_2 + IL_0012: ldc.i4.7 + IL_0013: ldc.i4.0 + IL_0014: ldloc.0 + IL_0015: ldloc.1 + IL_0016: call ""CustomHandler..ctor(int, int, int, string)"" + IL_001b: ldloca.s V_2 + IL_001d: ldstr ""literal"" + IL_0022: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0027: pop + IL_0028: ldloc.2 + IL_0029: callvirt ""string C.this[int, string, CustomHandler].get"" + IL_002e: call ""void System.Console.WriteLine(string)"" + IL_0033: ret +} +" + : @" +{ + // Code size 59 (0x3b) + .maxstack 8 + .locals init (int V_0, + string V_1, + CustomHandler V_2, + bool V_3) + IL_0000: newobj ""C..ctor()"" + IL_0005: ldc.i4.s 10 + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldstr ""str"" + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: ldc.i4.7 + IL_0011: ldc.i4.0 + IL_0012: ldloc.0 + IL_0013: ldloc.1 + IL_0014: ldloca.s V_3 + IL_0016: newobj ""CustomHandler..ctor(int, int, int, string, out bool)"" + IL_001b: stloc.2 + IL_001c: ldloc.3 + IL_001d: brfalse.s IL_002d + IL_001f: ldloca.s V_2 + IL_0021: ldstr ""literal"" + IL_0026: call ""bool CustomHandler.AppendLiteral(string)"" + IL_002b: br.s IL_002e + IL_002d: ldc.i4.0 + IL_002e: pop + IL_002f: ldloc.2 + IL_0030: callvirt ""string C.this[int, string, CustomHandler].get"" + IL_0035: call ""void System.Console.WriteLine(string)"" + IL_003a: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetIndexer("Item").Parameters.Skip(2).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { 0, 1 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_OnIndexerLvalue([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +var c = new C(); +c[10, ""str"", " + expression + @"] = """"; + +public class C +{ + public string this[int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", ""s"")] CustomHandler c] { set => Console.WriteLine(c.ToString()); } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i1, string s" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""i1:"" + i1.ToString()); + _builder.AppendLine(""s:"" + s); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @" +i1:10 +s:str +literal:literal +"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", (extraConstructorArg == "") + ? @" +{ + // Code size 52 (0x34) + .maxstack 8 + .locals init (int V_0, + string V_1, + CustomHandler V_2) + IL_0000: newobj ""C..ctor()"" + IL_0005: ldc.i4.s 10 + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldstr ""str"" + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: ldloca.s V_2 + IL_0012: ldc.i4.7 + IL_0013: ldc.i4.0 + IL_0014: ldloc.0 + IL_0015: ldloc.1 + IL_0016: call ""CustomHandler..ctor(int, int, int, string)"" + IL_001b: ldloca.s V_2 + IL_001d: ldstr ""literal"" + IL_0022: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0027: pop + IL_0028: ldloc.2 + IL_0029: ldstr """" + IL_002e: callvirt ""void C.this[int, string, CustomHandler].set"" + IL_0033: ret +} +" + : @" +{ + // Code size 59 (0x3b) + .maxstack 8 + .locals init (int V_0, + string V_1, + CustomHandler V_2, + bool V_3) + IL_0000: newobj ""C..ctor()"" + IL_0005: ldc.i4.s 10 + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldstr ""str"" + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: ldc.i4.7 + IL_0011: ldc.i4.0 + IL_0012: ldloc.0 + IL_0013: ldloc.1 + IL_0014: ldloca.s V_3 + IL_0016: newobj ""CustomHandler..ctor(int, int, int, string, out bool)"" + IL_001b: stloc.2 + IL_001c: ldloc.3 + IL_001d: brfalse.s IL_002d + IL_001f: ldloca.s V_2 + IL_0021: ldstr ""literal"" + IL_0026: call ""bool CustomHandler.AppendLiteral(string)"" + IL_002b: br.s IL_002e + IL_002d: ldc.i4.0 + IL_002e: pop + IL_002f: ldloc.2 + IL_0030: ldstr """" + IL_0035: callvirt ""void C.this[int, string, CustomHandler].set"" + IL_003a: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetIndexer("Item").Parameters.Skip(2).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { 0, 1 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_ThisParameter([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +(new C(5)).M((int)10, ""str"", " + expression + @"); + +public class C +{ + public int Prop { get; } + public C(int i) => Prop = i; + public void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", """", ""s"")] CustomHandler c) => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i1, C c, string s" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""i1:"" + i1.ToString()); + _builder.AppendLine(""c.Prop:"" + c.Prop.ToString()); + _builder.AppendLine(""s:"" + s); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @" +i1:10 +c.Prop:5 +s:str +literal:literal +"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", (extraConstructorArg == "") + ? @" +{ + // Code size 51 (0x33) + .maxstack 9 + .locals init (int V_0, + C V_1, + string V_2, + CustomHandler V_3) + IL_0000: ldc.i4.5 + IL_0001: newobj ""C..ctor(int)"" + IL_0006: stloc.1 + IL_0007: ldloc.1 + IL_0008: ldc.i4.s 10 + IL_000a: stloc.0 + IL_000b: ldloc.0 + IL_000c: ldstr ""str"" + IL_0011: stloc.2 + IL_0012: ldloc.2 + IL_0013: ldloca.s V_3 + IL_0015: ldc.i4.7 + IL_0016: ldc.i4.0 + IL_0017: ldloc.0 + IL_0018: ldloc.1 + IL_0019: ldloc.2 + IL_001a: call ""CustomHandler..ctor(int, int, int, C, string)"" + IL_001f: ldloca.s V_3 + IL_0021: ldstr ""literal"" + IL_0026: call ""bool CustomHandler.AppendLiteral(string)"" + IL_002b: pop + IL_002c: ldloc.3 + IL_002d: callvirt ""void C.M(int, string, CustomHandler)"" + IL_0032: ret +} +" + : @" +{ + // Code size 59 (0x3b) + .maxstack 9 + .locals init (int V_0, + C V_1, + string V_2, + CustomHandler V_3, + bool V_4) + IL_0000: ldc.i4.5 + IL_0001: newobj ""C..ctor(int)"" + IL_0006: stloc.1 + IL_0007: ldloc.1 + IL_0008: ldc.i4.s 10 + IL_000a: stloc.0 + IL_000b: ldloc.0 + IL_000c: ldstr ""str"" + IL_0011: stloc.2 + IL_0012: ldloc.2 + IL_0013: ldc.i4.7 + IL_0014: ldc.i4.0 + IL_0015: ldloc.0 + IL_0016: ldloc.1 + IL_0017: ldloc.2 + IL_0018: ldloca.s V_4 + IL_001a: newobj ""CustomHandler..ctor(int, int, int, C, string, out bool)"" + IL_001f: stloc.3 + IL_0020: ldloc.s V_4 + IL_0022: brfalse.s IL_0032 + IL_0024: ldloca.s V_3 + IL_0026: ldstr ""literal"" + IL_002b: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0030: br.s IL_0033 + IL_0032: ldc.i4.0 + IL_0033: pop + IL_0034: ldloc.3 + IL_0035: callvirt ""void C.M(int, string, CustomHandler)"" + IL_003a: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { 0, -1, 1 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [InlineData(@"$""""""literal""""""")] + [InlineData(@"$"""""" + +"""""" + $""""""literal""""""")] + public void InterpolatedStringHandlerArgumentAttribute_OnConstructor(string expression) + { + + var code = @" +using System; +using System.Runtime.CompilerServices; + +_ = new C(5, " + expression + @"); + +public class C +{ + public int Prop { get; } + public C(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")]CustomHandler c) => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i) : this(literalLength, formattedCount) + { + _builder.AppendLine(""i:"" + i.ToString()); + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, expectedOutput: @" +i:5 +literal:literal +"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 34 (0x22) + .maxstack 5 + .locals init (int V_0, + CustomHandler V_1) + IL_0000: ldc.i4.5 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldloca.s V_1 + IL_0005: ldc.i4.7 + IL_0006: ldc.i4.0 + IL_0007: ldloc.0 + IL_0008: call ""CustomHandler..ctor(int, int, int)"" + IL_000d: ldloca.s V_1 + IL_000f: ldstr ""literal"" + IL_0014: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0019: pop + IL_001a: ldloc.1 + IL_001b: newobj ""C..ctor(int, CustomHandler)"" + IL_0020: pop + IL_0021: ret +} +"); + } + + [Theory] + [CombinatorialData] + public void RefReturningMethodAsReceiver_RefParameter([CombinatorialValues("", ", out bool success")] string extraConstructorArg, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression, [CombinatorialValues("class", "struct")] string receiverType) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C c = new C(1); +GetC(ref c).M(" + expression + @"); +Console.WriteLine(c.I); + +ref C GetC(ref C c) +{ + Console.WriteLine(""GetC""); + return ref c; +} + +public " + receiverType + @" C +{ + public int I; + public C(int i) + { + I = i; + } + + public void M([InterpolatedStringHandlerArgument("""")]CustomHandler c) => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, ref C c" + extraConstructorArg + @") : this(literalLength, formattedCount) + { + c = new C(2); +" + (extraConstructorArg != "" ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + + comp.VerifyDiagnostics( + extraConstructorArg != "" ? + new[] { + // (6,1): error CS1620: Argument 3 must be passed with the 'ref' keyword + // GetC(ref c).M($"""literal""" + $""" + Diagnostic(ErrorCode.ERR_BadArgRef, "GetC(ref c)").WithArguments("3", "ref").WithLocation(6, 1), + // (6,15): error CS7036: There is no argument given that corresponds to the required formal parameter 'success' of 'CustomHandler.CustomHandler(int, int, ref C, out bool)' + // GetC(ref c).M($"""literal""" + $""" + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("success", "CustomHandler.CustomHandler(int, int, ref C, out bool)").WithLocation(6, 15) + } + : new[] { + // (6,1): error CS1620: Argument 3 must be passed with the 'ref' keyword + // GetC(ref c).M($"""literal""" + $""" + Diagnostic(ErrorCode.ERR_BadArgRef, "GetC(ref c)").WithArguments("3", "ref").WithLocation(6, 1) + }); + } + + [Theory] + [CombinatorialData] + public void RefReturningMethodAsReceiver_MismatchedRefness_01([CombinatorialValues("ref readonly", "")] string refness, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +C c = new C(1); +GetC().M(" + expression + @"); + +" + refness + @" C GetC() => throw null; + +public class C +{ + public C(int i) { } + public void M([InterpolatedStringHandlerArgument("""")]CustomHandler c) { } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, ref C c) : this(literalLength, formattedCount) { } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (5,1): error CS1620: Argument 3 must be passed with the 'ref' keyword + // GetC().M($"""literal""" + $""" + Diagnostic(ErrorCode.ERR_BadArgRef, "GetC()").WithArguments("3", "ref").WithLocation(5, 1)); + } + + [Theory] + [CombinatorialData] + public void RefReturningMethodAsReceiver_MismatchedRefness_02([CombinatorialValues("in", "")] string refness, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C c = new C(1); +GetC(ref c).M(" + expression + @"); + +ref C GetC(ref C c) => ref c; + +public class C +{ + public int I; + public C(int i) { I = i; } + public void M([InterpolatedStringHandlerArgument("""")]CustomHandler c) => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount," + refness + @" C c) : this(literalLength, formattedCount) + { + _builder.Append(c.I); + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + // Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. { Offset = 1 } + var verifier = CompileAndVerify( + new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, + expectedOutput: "1literal:literal", + symbolValidator: validator, + sourceSymbolValidator: validator, + verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.FailsILVerify : Verification.Skipped); + verifier.VerifyIL("", refness == "in" ? @" +{ + // Code size 46 (0x2e) + .maxstack 4 + .locals init (C V_0, //c + C& V_1, + CustomHandler V_2) + IL_0000: ldc.i4.1 + IL_0001: newobj ""C..ctor(int)"" + IL_0006: stloc.0 + IL_0007: ldloca.s V_0 + IL_0009: call ""ref C Program.<
$>g__GetC|0_0(ref C)"" + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: ldind.ref + IL_0011: ldc.i4.7 + IL_0012: ldc.i4.0 + IL_0013: ldloc.1 + IL_0014: newobj ""CustomHandler..ctor(int, int, in C)"" + IL_0019: stloc.2 + IL_001a: ldloca.s V_2 + IL_001c: ldstr ""literal"" + IL_0021: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0026: pop + IL_0027: ldloc.2 + IL_0028: callvirt ""void C.M(CustomHandler)"" + IL_002d: ret +} +" +: @" +{ + // Code size 48 (0x30) + .maxstack 5 + .locals init (C V_0, //c + C& V_1, + CustomHandler V_2) + IL_0000: ldc.i4.1 + IL_0001: newobj ""C..ctor(int)"" + IL_0006: stloc.0 + IL_0007: ldloca.s V_0 + IL_0009: call ""ref C Program.<
$>g__GetC|0_0(ref C)"" + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: ldind.ref + IL_0011: ldloca.s V_2 + IL_0013: ldc.i4.7 + IL_0014: ldc.i4.0 + IL_0015: ldloc.1 + IL_0016: ldind.ref + IL_0017: call ""CustomHandler..ctor(int, int, C)"" + IL_001c: ldloca.s V_2 + IL_001e: ldstr ""literal"" + IL_0023: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0028: pop + IL_0029: ldloc.2 + IL_002a: callvirt ""void C.M(CustomHandler)"" + IL_002f: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { -1 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory, CombinatorialData] + [WorkItem(56624, "https://github.com/dotnet/roslyn/issues/56624")] + public void RefOrOutParameter_AsReceiver([CombinatorialValues("ref", "out")] string parameterRefness, + [CombinatorialValues(@"$""""""literal""""""", @"$""""""literal"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C c = default; +localFunc(" + parameterRefness + @" c); + +void localFunc(" + parameterRefness + @" C c) +{ + c = new C(1); + c.M(" + expression + @"); +} + +public class C +{ + public int I; + public C(int i) { I = i; } + public void M([InterpolatedStringHandlerArgument("""")]CustomHandler c) => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount) + { + _builder.Append(c.I); + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, expectedOutput: "1literal:literal", symbolValidator: validator, sourceSymbolValidator: validator); + verifier.VerifyDiagnostics(); + verifier.VerifyIL($"Program.<
$>g__localFunc|0_0({parameterRefness} C)", @" +{ + // Code size 43 (0x2b) + .maxstack 5 + .locals init (C& V_0, + CustomHandler V_1) + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: newobj ""C..ctor(int)"" + IL_0007: stind.ref + IL_0008: ldarg.0 + IL_0009: stloc.0 + IL_000a: ldloc.0 + IL_000b: ldind.ref + IL_000c: ldloca.s V_1 + IL_000e: ldc.i4.7 + IL_000f: ldc.i4.0 + IL_0010: ldloc.0 + IL_0011: ldind.ref + IL_0012: call ""CustomHandler..ctor(int, int, C)"" + IL_0017: ldloca.s V_1 + IL_0019: ldstr ""literal"" + IL_001e: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0023: pop + IL_0024: ldloc.1 + IL_0025: callvirt ""void C.M(CustomHandler)"" + IL_002a: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { -1 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void StructReceiver_Rvalue(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +S s1 = new S { I = 1 }; +S s2 = new S { I = 2 }; + +s1.M(s2, " + expression + @"); + +public struct S +{ + public int I; + + public void M(S s2, [InterpolatedStringHandlerArgument("""", ""s2"")]CustomHandler handler) + { + Console.WriteLine(""s1.I:"" + this.I.ToString()); + Console.WriteLine(""s2.I:"" + s2.I.ToString()); + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, S s1, S s2) : this(literalLength, formattedCount) + { + s1.I = 3; + s2.I = 4; + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +s1.I:1 +s2.I:2"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 56 (0x38) + .maxstack 6 + .locals init (S V_0, //s2 + S V_1, + S V_2) + IL_0000: ldloca.s V_1 + IL_0002: initobj ""S"" + IL_0008: ldloca.s V_1 + IL_000a: ldc.i4.1 + IL_000b: stfld ""int S.I"" + IL_0010: ldloc.1 + IL_0011: ldloca.s V_1 + IL_0013: initobj ""S"" + IL_0019: ldloca.s V_1 + IL_001b: ldc.i4.2 + IL_001c: stfld ""int S.I"" + IL_0021: ldloc.1 + IL_0022: stloc.0 + IL_0023: stloc.1 + IL_0024: ldloca.s V_1 + IL_0026: ldloc.0 + IL_0027: stloc.2 + IL_0028: ldloc.2 + IL_0029: ldc.i4.0 + IL_002a: ldc.i4.0 + IL_002b: ldloc.1 + IL_002c: ldloc.2 + IL_002d: newobj ""CustomHandler..ctor(int, int, S, S)"" + IL_0032: call ""void S.M(S, CustomHandler)"" + IL_0037: ret +} +"); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void StructReceiver_Lvalue(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +S s1 = new S { I = 1 }; +S s2 = new S { I = 2 }; + +s1.M(ref s2, " + expression + @"); + +public struct S +{ + public int I; + + public void M(ref S s2, [InterpolatedStringHandlerArgument("""", ""s2"")]CustomHandler handler) + { + Console.WriteLine(""s1.I:"" + this.I.ToString()); + Console.WriteLine(""s2.I:"" + s2.I.ToString()); + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, ref S s1, ref S s2) : this(literalLength, formattedCount) + { + s1.I = 3; + s2.I = 4; + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (8,1): error CS1620: Argument 3 must be passed with the 'ref' keyword + // s1.M(ref s2, $""" + Diagnostic(ErrorCode.ERR_BadArgRef, "s1").WithArguments("3", "ref").WithLocation(8, 1)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void StructParameter_ByVal(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +S s = new S { I = 1 }; + +S.M(s, " + expression + @"); + +public struct S +{ + public int I; + + public static void M(S s, [InterpolatedStringHandlerArgument(""s"")]CustomHandler handler) + { + Console.WriteLine(""s.I:"" + s.I.ToString()); + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, S s) : this(literalLength, formattedCount) + { + s.I = 2; + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + + var verifier = CompileAndVerify(comp, expectedOutput: @"s.I:1"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 33 (0x21) + .maxstack 4 + .locals init (S V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj ""S"" + IL_0008: ldloca.s V_0 + IL_000a: ldc.i4.1 + IL_000b: stfld ""int S.I"" + IL_0010: ldloc.0 + IL_0011: stloc.0 + IL_0012: ldloc.0 + IL_0013: ldc.i4.0 + IL_0014: ldc.i4.0 + IL_0015: ldloc.0 + IL_0016: newobj ""CustomHandler..ctor(int, int, S)"" + IL_001b: call ""void S.M(S, CustomHandler)"" + IL_0020: ret +} +"); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void StructParameter_ByRef(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +S s = new S { I = 1 }; + +S.M(ref s, " + expression + @"); + +public struct S +{ + public int I; + + public static void M(ref S s, [InterpolatedStringHandlerArgument(""s"")]CustomHandler handler) + { + Console.WriteLine(""s.I:"" + s.I.ToString()); + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, ref S s) : this(literalLength, formattedCount) + { + s.I = 2; + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + + var verifier = CompileAndVerify(comp, expectedOutput: @"s.I:2"); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 36 (0x24) + .maxstack 4 + .locals init (S V_0, //s + S V_1, + S& V_2) + IL_0000: ldloca.s V_1 + IL_0002: initobj ""S"" + IL_0008: ldloca.s V_1 + IL_000a: ldc.i4.1 + IL_000b: stfld ""int S.I"" + IL_0010: ldloc.1 + IL_0011: stloc.0 + IL_0012: ldloca.s V_0 + IL_0014: stloc.2 + IL_0015: ldloc.2 + IL_0016: ldc.i4.0 + IL_0017: ldc.i4.0 + IL_0018: ldloc.2 + IL_0019: newobj ""CustomHandler..ctor(int, int, ref S)"" + IL_001e: call ""void S.M(ref S, CustomHandler)"" + IL_0023: ret +} +"); + } + + [Theory] + [CombinatorialData] + public void SideEffects(bool useBoolReturns, bool validityParameter, + [CombinatorialValues(@"$""""""literal""""""", @"$"""""" + +"""""" + $""""""literal""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +GetReceiver().M( + GetArg(""Unrelated parameter 1""), + GetArg(""Second value""), + GetArg(""Unrelated parameter 2""), + GetArg(""First value""), + " + expression + @", + GetArg(""Unrelated parameter 4"")); + +C GetReceiver() +{ + Console.WriteLine(""GetReceiver""); + return new C() { Prop = ""Prop"" }; +} + +string GetArg(string s) +{ + Console.WriteLine(s); + return s; +} + +public class C +{ + public string Prop { get; set; } + public void M(string param1, string param2, string param3, string param4, [InterpolatedStringHandlerArgument(""param4"", """", ""param2"")] CustomHandler c, string param6) + => Console.WriteLine(c.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, string s1, C c, string s2" + (validityParameter ? ", out bool success" : "") + @") + : this(literalLength, formattedCount) + { + Console.WriteLine(""Handler constructor""); + _builder.AppendLine(""s1:"" + s1); + _builder.AppendLine(""c.Prop:"" + c.Prop); + _builder.AppendLine(""s2:"" + s2); + " + (validityParameter ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns); + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, expectedOutput: @" +GetReceiver +Unrelated parameter 1 +Second value +Unrelated parameter 2 +First value +Handler constructor +Unrelated parameter 4 +s1:First value +c.Prop:Prop +s2:Second value +literal:literal +"); + verifier.VerifyDiagnostics(); + } + + [Theory] + [InlineData(@"$""""""literal""""""")] + [InlineData(@"$""""""literal"""""" + $"""""" + +""""""")] + public void InterpolatedStringHandlerArgumentsAttribute_ConversionFromArgumentType(string expression) + { + var code = @" +using System; +using System.Globalization; +using System.Runtime.CompilerServices; + +int i = 1; +C.M(i, " + expression + @"); + +public class C +{ + public static implicit operator C(int i) => throw null; + public static implicit operator C(double d) + { + Console.WriteLine(d.ToString(""G"", CultureInfo.InvariantCulture)); + return new C(); + } + public override string ToString() => ""C""; + + public static void M(double d, [InterpolatedStringHandlerArgument(""d"")] CustomHandler handler) => Console.WriteLine(handler.ToString()); +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount) { } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @" +1 +literal:literal +"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 39 (0x27) + .maxstack 5 + .locals init (double V_0, + CustomHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: conv.r8 + IL_0002: stloc.0 + IL_0003: ldloc.0 + IL_0004: ldloca.s V_1 + IL_0006: ldc.i4.7 + IL_0007: ldc.i4.0 + IL_0008: ldloc.0 + IL_0009: call ""C C.op_Implicit(double)"" + IL_000e: call ""CustomHandler..ctor(int, int, C)"" + IL_0013: ldloca.s V_1 + IL_0015: ldstr ""literal"" + IL_001a: call ""bool CustomHandler.AppendLiteral(string)"" + IL_001f: pop + IL_0020: ldloc.1 + IL_0021: call ""void C.M(double, CustomHandler)"" + IL_0026: ret +} +"); + + static void validator(ModuleSymbol module) + { + var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single(); + AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute", + cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString()); + Assert.Equal(new[] { 0 }, cParam.InterpolatedStringHandlerArgumentIndexes); + } + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentsAttribute_CompoundAssignment_Indexer_01(bool useBoolReturns, bool validityParameter, + [CombinatorialValues(@"$""""""literal{i}""""""", @"$""""""literal"""""" + $""""""{i}""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +int i = 3; +GetC()[GetInt(1), " + expression + @"] += GetInt(2); + +static C GetC() +{ + Console.WriteLine(""GetC""); + return new C() { Prop = 2 }; +} + +static int GetInt(int i) +{ + Console.WriteLine(""GetInt"" + i.ToString()); + return 1; +} + +public class C +{ + public int Prop { get; set; } + public int this[int arg1, [InterpolatedStringHandlerArgument(""arg1"", """")] CustomHandler c] + { + get + { + Console.WriteLine(""Indexer getter""); + return 0; + } + set + { + Console.WriteLine(""Indexer setter""); + Console.WriteLine(c.ToString()); + } + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int arg1, C c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount) + { + Console.WriteLine(""Handler constructor""); + _builder.AppendLine(""arg1:"" + arg1); + _builder.AppendLine(""C.Prop:"" + c.Prop.ToString()); + " + (validityParameter ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: useBoolReturns); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, expectedOutput: @" +GetC +GetInt1 +Handler constructor +Indexer getter +GetInt2 +Indexer setter +arg1:1 +C.Prop:2 +literal:literal +value:3 +alignment:0 +format: +"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", getIl()); + + string getIl() => (useBoolReturns, validityParameter) switch + { + (useBoolReturns: false, validityParameter: false) => @" +{ + // Code size 85 (0x55) + .maxstack 6 + .locals init (int V_0, //i + int V_1, + C V_2, + int V_3, + CustomHandler V_4, + CustomHandler V_5) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldc.i4.1 + IL_0009: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: stloc.3 + IL_0011: ldloca.s V_5 + IL_0013: ldc.i4.7 + IL_0014: ldc.i4.1 + IL_0015: ldloc.1 + IL_0016: ldloc.2 + IL_0017: call ""CustomHandler..ctor(int, int, int, C)"" + IL_001c: ldloca.s V_5 + IL_001e: ldstr ""literal"" + IL_0023: call ""void CustomHandler.AppendLiteral(string)"" + IL_0028: ldloca.s V_5 + IL_002a: ldloc.0 + IL_002b: box ""int"" + IL_0030: ldc.i4.0 + IL_0031: ldnull + IL_0032: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0037: ldloc.s V_5 + IL_0039: stloc.s V_4 + IL_003b: ldloc.2 + IL_003c: ldloc.3 + IL_003d: ldloc.s V_4 + IL_003f: ldloc.2 + IL_0040: ldloc.3 + IL_0041: ldloc.s V_4 + IL_0043: callvirt ""int C.this[int, CustomHandler].get"" + IL_0048: ldc.i4.2 + IL_0049: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_004e: add + IL_004f: callvirt ""void C.this[int, CustomHandler].set"" + IL_0054: ret +} +", + (useBoolReturns: false, validityParameter: true) => @" +{ + // Code size 95 (0x5f) + .maxstack 6 + .locals init (int V_0, //i + CustomHandler V_1, + bool V_2, + int V_3, + C V_4, + int V_5, + CustomHandler V_6) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.s V_4 + IL_0009: ldc.i4.1 + IL_000a: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000f: stloc.3 + IL_0010: ldloc.3 + IL_0011: stloc.s V_5 + IL_0013: ldc.i4.7 + IL_0014: ldc.i4.1 + IL_0015: ldloc.3 + IL_0016: ldloc.s V_4 + IL_0018: ldloca.s V_2 + IL_001a: newobj ""CustomHandler..ctor(int, int, int, C, out bool)"" + IL_001f: stloc.1 + IL_0020: ldloc.2 + IL_0021: brfalse.s IL_003e + IL_0023: ldloca.s V_1 + IL_0025: ldstr ""literal"" + IL_002a: call ""void CustomHandler.AppendLiteral(string)"" + IL_002f: ldloca.s V_1 + IL_0031: ldloc.0 + IL_0032: box ""int"" + IL_0037: ldc.i4.0 + IL_0038: ldnull + IL_0039: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_003e: ldloc.1 + IL_003f: stloc.s V_6 + IL_0041: ldloc.s V_4 + IL_0043: ldloc.s V_5 + IL_0045: ldloc.s V_6 + IL_0047: ldloc.s V_4 + IL_0049: ldloc.s V_5 + IL_004b: ldloc.s V_6 + IL_004d: callvirt ""int C.this[int, CustomHandler].get"" + IL_0052: ldc.i4.2 + IL_0053: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_0058: add + IL_0059: callvirt ""void C.this[int, CustomHandler].set"" + IL_005e: ret +} +", + (useBoolReturns: true, validityParameter: false) => @" +{ + // Code size 91 (0x5b) + .maxstack 6 + .locals init (int V_0, //i + int V_1, + C V_2, + int V_3, + CustomHandler V_4, + CustomHandler V_5) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldc.i4.1 + IL_0009: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: stloc.3 + IL_0011: ldloca.s V_5 + IL_0013: ldc.i4.7 + IL_0014: ldc.i4.1 + IL_0015: ldloc.1 + IL_0016: ldloc.2 + IL_0017: call ""CustomHandler..ctor(int, int, int, C)"" + IL_001c: ldloca.s V_5 + IL_001e: ldstr ""literal"" + IL_0023: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0028: brfalse.s IL_003b + IL_002a: ldloca.s V_5 + IL_002c: ldloc.0 + IL_002d: box ""int"" + IL_0032: ldc.i4.0 + IL_0033: ldnull + IL_0034: call ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_0039: br.s IL_003c + IL_003b: ldc.i4.0 + IL_003c: pop + IL_003d: ldloc.s V_5 + IL_003f: stloc.s V_4 + IL_0041: ldloc.2 + IL_0042: ldloc.3 + IL_0043: ldloc.s V_4 + IL_0045: ldloc.2 + IL_0046: ldloc.3 + IL_0047: ldloc.s V_4 + IL_0049: callvirt ""int C.this[int, CustomHandler].get"" + IL_004e: ldc.i4.2 + IL_004f: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_0054: add + IL_0055: callvirt ""void C.this[int, CustomHandler].set"" + IL_005a: ret +} +", + (useBoolReturns: true, validityParameter: true) => @" +{ + // Code size 97 (0x61) + .maxstack 6 + .locals init (int V_0, //i + int V_1, + C V_2, + int V_3, + CustomHandler V_4, + CustomHandler V_5, + bool V_6) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldc.i4.1 + IL_0009: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: stloc.3 + IL_0011: ldc.i4.7 + IL_0012: ldc.i4.1 + IL_0013: ldloc.1 + IL_0014: ldloc.2 + IL_0015: ldloca.s V_6 + IL_0017: newobj ""CustomHandler..ctor(int, int, int, C, out bool)"" + IL_001c: stloc.s V_5 + IL_001e: ldloc.s V_6 + IL_0020: brfalse.s IL_0041 + IL_0022: ldloca.s V_5 + IL_0024: ldstr ""literal"" + IL_0029: call ""bool CustomHandler.AppendLiteral(string)"" + IL_002e: brfalse.s IL_0041 + IL_0030: ldloca.s V_5 + IL_0032: ldloc.0 + IL_0033: box ""int"" + IL_0038: ldc.i4.0 + IL_0039: ldnull + IL_003a: call ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_003f: br.s IL_0042 + IL_0041: ldc.i4.0 + IL_0042: pop + IL_0043: ldloc.s V_5 + IL_0045: stloc.s V_4 + IL_0047: ldloc.2 + IL_0048: ldloc.3 + IL_0049: ldloc.s V_4 + IL_004b: ldloc.2 + IL_004c: ldloc.3 + IL_004d: ldloc.s V_4 + IL_004f: callvirt ""int C.this[int, CustomHandler].get"" + IL_0054: ldc.i4.2 + IL_0055: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_005a: add + IL_005b: callvirt ""void C.this[int, CustomHandler].set"" + IL_0060: ret +} +", + }; + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentsAttribute_CompoundAssignment_Indexer_02(bool useBoolReturns, bool validityParameter, + [CombinatorialValues(@"$""""""literal{i}""""""", @"$""""""literal"""""" + $""""""{i}""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +int i = 3; +GetC()[GetInt(1), " + expression + @"] += GetInt(2); + +static C GetC() +{ + Console.WriteLine(""GetC""); + return new C() { Prop = 2 }; +} + +static int GetInt(int i) +{ + Console.WriteLine(""GetInt"" + i.ToString()); + return 1; +} + +public class C +{ + private int field; + public int Prop { get; set; } + public ref int this[int arg1, [InterpolatedStringHandlerArgument(""arg1"", """")] CustomHandler c] + { + get + { + Console.WriteLine(""Indexer getter""); + Console.WriteLine(c.ToString()); + return ref field; + } + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int arg1, C c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount) + { + Console.WriteLine(""Handler constructor""); + _builder.AppendLine(""arg1:"" + arg1); + _builder.AppendLine(""C.Prop:"" + c.Prop.ToString()); + " + (validityParameter ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: useBoolReturns); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, expectedOutput: @" +GetC +GetInt1 +Handler constructor +Indexer getter +arg1:1 +C.Prop:2 +literal:literal +value:3 +alignment:0 +format: + +GetInt2 +"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", getIl()); + + string getIl() => (useBoolReturns, validityParameter) switch + { + (useBoolReturns: false, validityParameter: false) => @" +{ + // Code size 72 (0x48) + .maxstack 7 + .locals init (int V_0, //i + int V_1, + C V_2, + CustomHandler V_3) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldloc.2 + IL_0009: ldc.i4.1 + IL_000a: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: ldloca.s V_3 + IL_0013: ldc.i4.7 + IL_0014: ldc.i4.1 + IL_0015: ldloc.1 + IL_0016: ldloc.2 + IL_0017: call ""CustomHandler..ctor(int, int, int, C)"" + IL_001c: ldloca.s V_3 + IL_001e: ldstr ""literal"" + IL_0023: call ""void CustomHandler.AppendLiteral(string)"" + IL_0028: ldloca.s V_3 + IL_002a: ldloc.0 + IL_002b: box ""int"" + IL_0030: ldc.i4.0 + IL_0031: ldnull + IL_0032: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0037: ldloc.3 + IL_0038: callvirt ""ref int C.this[int, CustomHandler].get"" + IL_003d: dup + IL_003e: ldind.i4 + IL_003f: ldc.i4.2 + IL_0040: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_0045: add + IL_0046: stind.i4 + IL_0047: ret +} +", + (useBoolReturns: false, validityParameter: true) => @" +{ + // Code size 81 (0x51) + .maxstack 6 + .locals init (int V_0, //i + int V_1, + C V_2, + int V_3, + CustomHandler V_4, + bool V_5) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldloc.2 + IL_0009: ldc.i4.1 + IL_000a: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: stloc.3 + IL_0012: ldc.i4.7 + IL_0013: ldc.i4.1 + IL_0014: ldloc.1 + IL_0015: ldloc.2 + IL_0016: ldloca.s V_5 + IL_0018: newobj ""CustomHandler..ctor(int, int, int, C, out bool)"" + IL_001d: stloc.s V_4 + IL_001f: ldloc.s V_5 + IL_0021: brfalse.s IL_003e + IL_0023: ldloca.s V_4 + IL_0025: ldstr ""literal"" + IL_002a: call ""void CustomHandler.AppendLiteral(string)"" + IL_002f: ldloca.s V_4 + IL_0031: ldloc.0 + IL_0032: box ""int"" + IL_0037: ldc.i4.0 + IL_0038: ldnull + IL_0039: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_003e: ldloc.3 + IL_003f: ldloc.s V_4 + IL_0041: callvirt ""ref int C.this[int, CustomHandler].get"" + IL_0046: dup + IL_0047: ldind.i4 + IL_0048: ldc.i4.2 + IL_0049: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_004e: add + IL_004f: stind.i4 + IL_0050: ret +} +", + (useBoolReturns: true, validityParameter: false) => @" +{ + // Code size 78 (0x4e) + .maxstack 7 + .locals init (int V_0, //i + int V_1, + C V_2, + CustomHandler V_3) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldloc.2 + IL_0009: ldc.i4.1 + IL_000a: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: ldloca.s V_3 + IL_0013: ldc.i4.7 + IL_0014: ldc.i4.1 + IL_0015: ldloc.1 + IL_0016: ldloc.2 + IL_0017: call ""CustomHandler..ctor(int, int, int, C)"" + IL_001c: ldloca.s V_3 + IL_001e: ldstr ""literal"" + IL_0023: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0028: brfalse.s IL_003b + IL_002a: ldloca.s V_3 + IL_002c: ldloc.0 + IL_002d: box ""int"" + IL_0032: ldc.i4.0 + IL_0033: ldnull + IL_0034: call ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_0039: br.s IL_003c + IL_003b: ldc.i4.0 + IL_003c: pop + IL_003d: ldloc.3 + IL_003e: callvirt ""ref int C.this[int, CustomHandler].get"" + IL_0043: dup + IL_0044: ldind.i4 + IL_0045: ldc.i4.2 + IL_0046: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_004b: add + IL_004c: stind.i4 + IL_004d: ret +} +", + (useBoolReturns: true, validityParameter: true) => @" +{ + // Code size 83 (0x53) + .maxstack 7 + .locals init (int V_0, //i + int V_1, + C V_2, + CustomHandler V_3, + bool V_4) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldloc.2 + IL_0009: ldc.i4.1 + IL_000a: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: ldc.i4.7 + IL_0012: ldc.i4.1 + IL_0013: ldloc.1 + IL_0014: ldloc.2 + IL_0015: ldloca.s V_4 + IL_0017: newobj ""CustomHandler..ctor(int, int, int, C, out bool)"" + IL_001c: stloc.3 + IL_001d: ldloc.s V_4 + IL_001f: brfalse.s IL_0040 + IL_0021: ldloca.s V_3 + IL_0023: ldstr ""literal"" + IL_0028: call ""bool CustomHandler.AppendLiteral(string)"" + IL_002d: brfalse.s IL_0040 + IL_002f: ldloca.s V_3 + IL_0031: ldloc.0 + IL_0032: box ""int"" + IL_0037: ldc.i4.0 + IL_0038: ldnull + IL_0039: call ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_003e: br.s IL_0041 + IL_0040: ldc.i4.0 + IL_0041: pop + IL_0042: ldloc.3 + IL_0043: callvirt ""ref int C.this[int, CustomHandler].get"" + IL_0048: dup + IL_0049: ldind.i4 + IL_004a: ldc.i4.2 + IL_004b: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_0050: add + IL_0051: stind.i4 + IL_0052: ret +} +", + }; + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentsAttribute_CompoundAssignment_RefReturningMethod(bool useBoolReturns, bool validityParameter, + [CombinatorialValues(@"$""""""literal{i}""""""", @"$""""""literal"""""" + $""""""{i}""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +int i = 3; +GetC().M(GetInt(1), " + expression + @") += GetInt(2); + +static C GetC() +{ + Console.WriteLine(""GetC""); + return new C() { Prop = 2 }; +} + +static int GetInt(int i) +{ + Console.WriteLine(""GetInt"" + i.ToString()); + return 1; +} + +public class C +{ + private int field; + public int Prop { get; set; } + public ref int M(int arg1, [InterpolatedStringHandlerArgument(""arg1"", """")] CustomHandler c) + { + Console.WriteLine(""M""); + Console.WriteLine(c.ToString()); + return ref field; + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int arg1, C c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount) + { + Console.WriteLine(""Handler constructor""); + _builder.AppendLine(""arg1:"" + arg1); + _builder.AppendLine(""C.Prop:"" + c.Prop.ToString()); + " + (validityParameter ? "success = true;" : "") + @" + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: useBoolReturns); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, expectedOutput: @" +GetC +GetInt1 +Handler constructor +M +arg1:1 +C.Prop:2 +literal:literal +value:3 +alignment:0 +format: + +GetInt2 +"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", getIl()); + + string getIl() => (useBoolReturns, validityParameter) switch + { + (useBoolReturns: false, validityParameter: false) => @" +{ + // Code size 72 (0x48) + .maxstack 7 + .locals init (int V_0, //i + int V_1, + C V_2, + CustomHandler V_3) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldloc.2 + IL_0009: ldc.i4.1 + IL_000a: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: ldloca.s V_3 + IL_0013: ldc.i4.7 + IL_0014: ldc.i4.1 + IL_0015: ldloc.1 + IL_0016: ldloc.2 + IL_0017: call ""CustomHandler..ctor(int, int, int, C)"" + IL_001c: ldloca.s V_3 + IL_001e: ldstr ""literal"" + IL_0023: call ""void CustomHandler.AppendLiteral(string)"" + IL_0028: ldloca.s V_3 + IL_002a: ldloc.0 + IL_002b: box ""int"" + IL_0030: ldc.i4.0 + IL_0031: ldnull + IL_0032: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0037: ldloc.3 + IL_0038: callvirt ""ref int C.M(int, CustomHandler)"" + IL_003d: dup + IL_003e: ldind.i4 + IL_003f: ldc.i4.2 + IL_0040: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_0045: add + IL_0046: stind.i4 + IL_0047: ret +} +", + (useBoolReturns: false, validityParameter: true) => @" +{ + // Code size 81 (0x51) + .maxstack 6 + .locals init (int V_0, //i + int V_1, + C V_2, + int V_3, + CustomHandler V_4, + bool V_5) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldloc.2 + IL_0009: ldc.i4.1 + IL_000a: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: stloc.3 + IL_0012: ldc.i4.7 + IL_0013: ldc.i4.1 + IL_0014: ldloc.1 + IL_0015: ldloc.2 + IL_0016: ldloca.s V_5 + IL_0018: newobj ""CustomHandler..ctor(int, int, int, C, out bool)"" + IL_001d: stloc.s V_4 + IL_001f: ldloc.s V_5 + IL_0021: brfalse.s IL_003e + IL_0023: ldloca.s V_4 + IL_0025: ldstr ""literal"" + IL_002a: call ""void CustomHandler.AppendLiteral(string)"" + IL_002f: ldloca.s V_4 + IL_0031: ldloc.0 + IL_0032: box ""int"" + IL_0037: ldc.i4.0 + IL_0038: ldnull + IL_0039: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_003e: ldloc.3 + IL_003f: ldloc.s V_4 + IL_0041: callvirt ""ref int C.M(int, CustomHandler)"" + IL_0046: dup + IL_0047: ldind.i4 + IL_0048: ldc.i4.2 + IL_0049: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_004e: add + IL_004f: stind.i4 + IL_0050: ret +} +", + (useBoolReturns: true, validityParameter: false) => @" +{ + // Code size 78 (0x4e) + .maxstack 7 + .locals init (int V_0, //i + int V_1, + C V_2, + CustomHandler V_3) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldloc.2 + IL_0009: ldc.i4.1 + IL_000a: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: ldloca.s V_3 + IL_0013: ldc.i4.7 + IL_0014: ldc.i4.1 + IL_0015: ldloc.1 + IL_0016: ldloc.2 + IL_0017: call ""CustomHandler..ctor(int, int, int, C)"" + IL_001c: ldloca.s V_3 + IL_001e: ldstr ""literal"" + IL_0023: call ""bool CustomHandler.AppendLiteral(string)"" + IL_0028: brfalse.s IL_003b + IL_002a: ldloca.s V_3 + IL_002c: ldloc.0 + IL_002d: box ""int"" + IL_0032: ldc.i4.0 + IL_0033: ldnull + IL_0034: call ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_0039: br.s IL_003c + IL_003b: ldc.i4.0 + IL_003c: pop + IL_003d: ldloc.3 + IL_003e: callvirt ""ref int C.M(int, CustomHandler)"" + IL_0043: dup + IL_0044: ldind.i4 + IL_0045: ldc.i4.2 + IL_0046: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_004b: add + IL_004c: stind.i4 + IL_004d: ret +} +", + (useBoolReturns: true, validityParameter: true) => @" +{ + // Code size 83 (0x53) + .maxstack 7 + .locals init (int V_0, //i + int V_1, + C V_2, + CustomHandler V_3, + bool V_4) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: call ""C Program.<
$>g__GetC|0_0()"" + IL_0007: stloc.2 + IL_0008: ldloc.2 + IL_0009: ldc.i4.1 + IL_000a: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: ldc.i4.7 + IL_0012: ldc.i4.1 + IL_0013: ldloc.1 + IL_0014: ldloc.2 + IL_0015: ldloca.s V_4 + IL_0017: newobj ""CustomHandler..ctor(int, int, int, C, out bool)"" + IL_001c: stloc.3 + IL_001d: ldloc.s V_4 + IL_001f: brfalse.s IL_0040 + IL_0021: ldloca.s V_3 + IL_0023: ldstr ""literal"" + IL_0028: call ""bool CustomHandler.AppendLiteral(string)"" + IL_002d: brfalse.s IL_0040 + IL_002f: ldloca.s V_3 + IL_0031: ldloc.0 + IL_0032: box ""int"" + IL_0037: ldc.i4.0 + IL_0038: ldnull + IL_0039: call ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_003e: br.s IL_0041 + IL_0040: ldc.i4.0 + IL_0041: pop + IL_0042: ldloc.3 + IL_0043: callvirt ""ref int C.M(int, CustomHandler)"" + IL_0048: dup + IL_0049: ldind.i4 + IL_004a: ldc.i4.2 + IL_004b: call ""int Program.<
$>g__GetInt|0_1(int)"" + IL_0050: add + IL_0051: stind.i4 + IL_0052: ret +} +", + }; + } + + [Theory] + [InlineData(@"$""""""literal""""""")] + [InlineData(@"$"""""" + +"""""" + $""""""literal""""""")] + public void InterpolatedStringHandlerArgumentsAttribute_CollectionInitializerAdd(string expression) + { + var code = @" +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +_ = new C(1) { " + expression + @" }; + +public class C : IEnumerable +{ + public int Field; + + public C(int i) + { + Field = i; + } + + public void Add([InterpolatedStringHandlerArgument("""")] CustomHandler c) + { + Console.WriteLine(c.ToString()); + } + + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount) + { + _builder.AppendLine(""c.Field:"" + c.Field.ToString()); + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, expectedOutput: @" +c.Field:1 +literal:literal +"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 37 (0x25) + .maxstack 5 + .locals init (C V_0, + CustomHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: newobj ""C..ctor(int)"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldloca.s V_1 + IL_000a: ldc.i4.7 + IL_000b: ldc.i4.0 + IL_000c: ldloc.0 + IL_000d: call ""CustomHandler..ctor(int, int, C)"" + IL_0012: ldloca.s V_1 + IL_0014: ldstr ""literal"" + IL_0019: call ""void CustomHandler.AppendLiteral(string)"" + IL_001e: ldloc.1 + IL_001f: callvirt ""void C.Add(CustomHandler)"" + IL_0024: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""literal""""""")] + [InlineData(@"$"""""" + +"""""" + $""""""literal""""""")] + public void InterpolatedStringHandlerArgumentsAttribute_DictionaryInitializer(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +_ = new C(1) { [" + expression + @"] = 1 }; + +public class C +{ + public int Field; + + public C(int i) + { + Field = i; + } + + public int this[[InterpolatedStringHandlerArgument("""")] CustomHandler c] + { + set => Console.WriteLine(c.ToString()); + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount) + { + _builder.AppendLine(""c.Field:"" + c.Field.ToString()); + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + comp.VerifyDiagnostics( + // (5,17): error CS8976: Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + // _ = new C(1) { [$"literal"] = 1 }; + Diagnostic(ErrorCode.ERR_InterpolatedStringsReferencingInstanceCannotBeInObjectInitializers, expression).WithLocation(5, 17)); + } + + [Theory] + [CombinatorialData] + public void InterpolatedStringHandlerArgumentAttribute_AttributeOnAppendFormatCall(bool useBoolReturns, bool validityParameter, + [CombinatorialValues(@"$""""""{$""""""Inner string""""""}{2}""""""", @"$""""""{$""""""Inner string""""""}"""""" + $""""""{2}""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C.M(1, " + expression + @"); + +class C +{ + public static void M(int i, [InterpolatedStringHandlerArgument(""i"")]CustomHandler handler) + { + Console.WriteLine(handler.ToString()); + } +} + +public partial class CustomHandler +{ + private int I = 0; + + public CustomHandler(int literalLength, int formattedCount, int i" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount) + { + Console.WriteLine(""int constructor""); + I = i; + " + (validityParameter ? "success = true;" : "") + @" + } + + public CustomHandler(int literalLength, int formattedCount, CustomHandler c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount) + { + Console.WriteLine(""CustomHandler constructor""); + _builder.AppendLine(""c.I:"" + c.I.ToString()); + " + (validityParameter ? "success = true;" : "") + @" + } + + public " + (useBoolReturns ? "bool" : "void") + @" AppendFormatted([InterpolatedStringHandlerArgument("""")]CustomHandler c) + { + _builder.AppendLine(""CustomHandler AppendFormatted""); + _builder.Append(c.ToString()); + " + (useBoolReturns ? "return true;" : "") + @" + } +} +"; + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: useBoolReturns); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, expectedOutput: @" +int constructor +CustomHandler constructor +CustomHandler AppendFormatted +c.I:1 +literal:Inner string +value:2 +alignment:0 +format: +"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", getIl()); + + string getIl() => (useBoolReturns, validityParameter) switch + { + (useBoolReturns: false, validityParameter: false) => @" +{ + // Code size 59 (0x3b) + .maxstack 6 + .locals init (int V_0, + CustomHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.2 + IL_0005: ldloc.0 + IL_0006: newobj ""CustomHandler..ctor(int, int, int)"" + IL_000b: dup + IL_000c: stloc.1 + IL_000d: ldloc.1 + IL_000e: ldc.i4.s 12 + IL_0010: ldc.i4.0 + IL_0011: ldloc.1 + IL_0012: newobj ""CustomHandler..ctor(int, int, CustomHandler)"" + IL_0017: dup + IL_0018: ldstr ""Inner string"" + IL_001d: callvirt ""void CustomHandler.AppendLiteral(string)"" + IL_0022: callvirt ""void CustomHandler.AppendFormatted(CustomHandler)"" + IL_0027: dup + IL_0028: ldc.i4.2 + IL_0029: box ""int"" + IL_002e: ldc.i4.0 + IL_002f: ldnull + IL_0030: callvirt ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0035: call ""void C.M(int, CustomHandler)"" + IL_003a: ret +} +", + (useBoolReturns: false, validityParameter: true) => @" +{ + // Code size 77 (0x4d) + .maxstack 6 + .locals init (int V_0, + CustomHandler V_1, + bool V_2, + CustomHandler V_3, + CustomHandler V_4, + bool V_5) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.2 + IL_0005: ldloc.0 + IL_0006: ldloca.s V_2 + IL_0008: newobj ""CustomHandler..ctor(int, int, int, out bool)"" + IL_000d: stloc.1 + IL_000e: ldloc.2 + IL_000f: brfalse.s IL_0046 + IL_0011: ldloc.1 + IL_0012: stloc.3 + IL_0013: ldloc.3 + IL_0014: ldc.i4.s 12 + IL_0016: ldc.i4.0 + IL_0017: ldloc.3 + IL_0018: ldloca.s V_5 + IL_001a: newobj ""CustomHandler..ctor(int, int, CustomHandler, out bool)"" + IL_001f: stloc.s V_4 + IL_0021: ldloc.s V_5 + IL_0023: brfalse.s IL_0031 + IL_0025: ldloc.s V_4 + IL_0027: ldstr ""Inner string"" + IL_002c: callvirt ""void CustomHandler.AppendLiteral(string)"" + IL_0031: ldloc.s V_4 + IL_0033: callvirt ""void CustomHandler.AppendFormatted(CustomHandler)"" + IL_0038: ldloc.1 + IL_0039: ldc.i4.2 + IL_003a: box ""int"" + IL_003f: ldc.i4.0 + IL_0040: ldnull + IL_0041: callvirt ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0046: ldloc.1 + IL_0047: call ""void C.M(int, CustomHandler)"" + IL_004c: ret +} +", + (useBoolReturns: true, validityParameter: false) => @" +{ + // Code size 68 (0x44) + .maxstack 5 + .locals init (int V_0, + CustomHandler V_1, + CustomHandler V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.2 + IL_0005: ldloc.0 + IL_0006: newobj ""CustomHandler..ctor(int, int, int)"" + IL_000b: stloc.1 + IL_000c: ldloc.1 + IL_000d: stloc.2 + IL_000e: ldloc.2 + IL_000f: ldc.i4.s 12 + IL_0011: ldc.i4.0 + IL_0012: ldloc.2 + IL_0013: newobj ""CustomHandler..ctor(int, int, CustomHandler)"" + IL_0018: dup + IL_0019: ldstr ""Inner string"" + IL_001e: callvirt ""bool CustomHandler.AppendLiteral(string)"" + IL_0023: pop + IL_0024: callvirt ""bool CustomHandler.AppendFormatted(CustomHandler)"" + IL_0029: brfalse.s IL_003b + IL_002b: ldloc.1 + IL_002c: ldc.i4.2 + IL_002d: box ""int"" + IL_0032: ldc.i4.0 + IL_0033: ldnull + IL_0034: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_0039: br.s IL_003c + IL_003b: ldc.i4.0 + IL_003c: pop + IL_003d: ldloc.1 + IL_003e: call ""void C.M(int, CustomHandler)"" + IL_0043: ret +} +", + (useBoolReturns: true, validityParameter: true) => @" +{ + // Code size 87 (0x57) + .maxstack 6 + .locals init (int V_0, + CustomHandler V_1, + bool V_2, + CustomHandler V_3, + CustomHandler V_4, + bool V_5) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.2 + IL_0005: ldloc.0 + IL_0006: ldloca.s V_2 + IL_0008: newobj ""CustomHandler..ctor(int, int, int, out bool)"" + IL_000d: stloc.1 + IL_000e: ldloc.2 + IL_000f: brfalse.s IL_004e + IL_0011: ldloc.1 + IL_0012: stloc.3 + IL_0013: ldloc.3 + IL_0014: ldc.i4.s 12 + IL_0016: ldc.i4.0 + IL_0017: ldloc.3 + IL_0018: ldloca.s V_5 + IL_001a: newobj ""CustomHandler..ctor(int, int, CustomHandler, out bool)"" + IL_001f: stloc.s V_4 + IL_0021: ldloc.s V_5 + IL_0023: brfalse.s IL_0033 + IL_0025: ldloc.s V_4 + IL_0027: ldstr ""Inner string"" + IL_002c: callvirt ""bool CustomHandler.AppendLiteral(string)"" + IL_0031: br.s IL_0034 + IL_0033: ldc.i4.0 + IL_0034: pop + IL_0035: ldloc.s V_4 + IL_0037: callvirt ""bool CustomHandler.AppendFormatted(CustomHandler)"" + IL_003c: brfalse.s IL_004e + IL_003e: ldloc.1 + IL_003f: ldc.i4.2 + IL_0040: box ""int"" + IL_0045: ldc.i4.0 + IL_0046: ldnull + IL_0047: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)"" + IL_004c: br.s IL_004f + IL_004e: ldc.i4.0 + IL_004f: pop + IL_0050: ldloc.1 + IL_0051: call ""void C.M(int, CustomHandler)"" + IL_0056: ret +} +", + }; + } + + [Theory] + [InlineData(@"$""""""literal""""""")] + [InlineData(@"$"""""" + +"""""" + $""""""literal""""""")] + public void DiscardsUsedAsParameters(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; +C.M(out _, " + expression + @"); + +public class C +{ + public static void M(out int i, [InterpolatedStringHandlerArgument(""i"")]CustomHandler c) + { + i = 0; + Console.WriteLine(c.ToString()); + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, out int i) : this(literalLength, formattedCount) + { + i = 1; + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, expectedOutput: @"literal:literal"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 31 (0x1f) + .maxstack 4 + .locals init (int V_0, + CustomHandler V_1) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.7 + IL_0003: ldc.i4.0 + IL_0004: ldloca.s V_0 + IL_0006: newobj ""CustomHandler..ctor(int, int, out int)"" + IL_000b: stloc.1 + IL_000c: ldloca.s V_1 + IL_000e: ldstr ""literal"" + IL_0013: call ""void CustomHandler.AppendLiteral(string)"" + IL_0018: ldloc.1 + IL_0019: call ""void C.M(out int, CustomHandler)"" + IL_001e: ret +} +"); + } + + [Fact] + public void DiscardsUsedAsParameters_DefinedInVB() + { + var vb = @" +Imports System +Imports System.Runtime.CompilerServices +Imports System.Runtime.InteropServices +Public Class C + Public Shared Sub M( ByRef i As Integer, c As CustomHandler) + Console.WriteLine(i) + End Sub +End Class + + +Public Structure CustomHandler + Public Sub New(literalLength As Integer, formattedCount As Integer, ByRef i As Integer) + i = 1 + End Sub +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vb, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var code = @"C.M(out _, $"""""" + +"""""");"; + + var comp = CreateCompilation(code, new[] { vbComp.EmitToImageReference() }); + var verifier = CompileAndVerify(comp, expectedOutput: @"1"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 17 (0x11) + .maxstack 4 + .locals init (int V_0) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.0 + IL_0003: ldc.i4.0 + IL_0004: ldloca.s V_0 + IL_0006: newobj ""CustomHandler..ctor(int, int, out int)"" + IL_000b: call ""void C.M(out int, CustomHandler)"" + IL_0010: ret +} +"); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void DisallowedInExpressionTrees(string expression) + { + var code = @" +using System; +using System.Linq.Expressions; + +Expression> expr = () => " + expression + @"; +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, handler }); + comp.VerifyDiagnostics( + // (5,46): error CS8952: An expression tree may not contain an interpolated string handler conversion. + // Expression> expr = () => $""; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsInterpolatedStringHandlerConversion, expression).WithLocation(5, 46)); + } + + [Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")] + public void AsStringInExpressionTrees_01() + { + var code = @" +using System; +using System.Linq.Expressions; + +Expression> e = o => $""""""{o.Length}"""""";"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }); + var verifier = CompileAndVerify(comp); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("", @" +{ + // Code size 127 (0x7f) + .maxstack 7 + .locals init (System.Linq.Expressions.ParameterExpression V_0) + IL_0000: ldtoken ""string"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""o"" + IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" + IL_0014: stloc.0 + IL_0015: ldnull + IL_0016: ldtoken ""string string.Format(string, object)"" + IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_0020: castclass ""System.Reflection.MethodInfo"" + IL_0025: ldc.i4.2 + IL_0026: newarr ""System.Linq.Expressions.Expression"" + IL_002b: dup + IL_002c: ldc.i4.0 + IL_002d: ldstr ""{0}"" + IL_0032: ldtoken ""string"" + IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0041: stelem.ref + IL_0042: dup + IL_0043: ldc.i4.1 + IL_0044: ldloc.0 + IL_0045: ldtoken ""int string.Length.get"" + IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_004f: castclass ""System.Reflection.MethodInfo"" + IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)"" + IL_0059: ldtoken ""object"" + IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_0068: stelem.ref + IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" + IL_006e: ldc.i4.1 + IL_006f: newarr ""System.Linq.Expressions.ParameterExpression"" + IL_0074: dup + IL_0075: ldc.i4.0 + IL_0076: ldloc.0 + IL_0077: stelem.ref + IL_0078: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_007d: pop + IL_007e: ret +} +"); + } + + [Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")] + public void AsStringInExpressionTrees_02() + { + var code = @" +using System.Linq.Expressions; + +Expression e = (string o) => $""""""{o.Length}"""""";"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }); + var verifier = CompileAndVerify(comp); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("", @" +{ + // Code size 127 (0x7f) + .maxstack 7 + .locals init (System.Linq.Expressions.ParameterExpression V_0) + IL_0000: ldtoken ""string"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""o"" + IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" + IL_0014: stloc.0 + IL_0015: ldnull + IL_0016: ldtoken ""string string.Format(string, object)"" + IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_0020: castclass ""System.Reflection.MethodInfo"" + IL_0025: ldc.i4.2 + IL_0026: newarr ""System.Linq.Expressions.Expression"" + IL_002b: dup + IL_002c: ldc.i4.0 + IL_002d: ldstr ""{0}"" + IL_0032: ldtoken ""string"" + IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0041: stelem.ref + IL_0042: dup + IL_0043: ldc.i4.1 + IL_0044: ldloc.0 + IL_0045: ldtoken ""int string.Length.get"" + IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_004f: castclass ""System.Reflection.MethodInfo"" + IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)"" + IL_0059: ldtoken ""object"" + IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_0068: stelem.ref + IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" + IL_006e: ldc.i4.1 + IL_006f: newarr ""System.Linq.Expressions.ParameterExpression"" + IL_0074: dup + IL_0075: ldc.i4.0 + IL_0076: ldloc.0 + IL_0077: stelem.ref + IL_0078: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_007d: pop + IL_007e: ret +} +"); + } + + [Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")] + public void AsStringInExpressionTrees_03() + { + var code = @" +using System; +using System.Linq.Expressions; + +Expression>> e = () => o => $""""""{o.Length}"""""";"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }); + var verifier = CompileAndVerify(comp); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("", @" +{ + // Code size 137 (0x89) + .maxstack 7 + .locals init (System.Linq.Expressions.ParameterExpression V_0) + IL_0000: ldtoken ""string"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""o"" + IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" + IL_0014: stloc.0 + IL_0015: ldnull + IL_0016: ldtoken ""string string.Format(string, object)"" + IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_0020: castclass ""System.Reflection.MethodInfo"" + IL_0025: ldc.i4.2 + IL_0026: newarr ""System.Linq.Expressions.Expression"" + IL_002b: dup + IL_002c: ldc.i4.0 + IL_002d: ldstr ""{0}"" + IL_0032: ldtoken ""string"" + IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0041: stelem.ref + IL_0042: dup + IL_0043: ldc.i4.1 + IL_0044: ldloc.0 + IL_0045: ldtoken ""int string.Length.get"" + IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_004f: castclass ""System.Reflection.MethodInfo"" + IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)"" + IL_0059: ldtoken ""object"" + IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_0068: stelem.ref + IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" + IL_006e: ldc.i4.1 + IL_006f: newarr ""System.Linq.Expressions.ParameterExpression"" + IL_0074: dup + IL_0075: ldc.i4.0 + IL_0076: ldloc.0 + IL_0077: stelem.ref + IL_0078: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_007d: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty()"" + IL_0082: call ""System.Linq.Expressions.Expression>> System.Linq.Expressions.Expression.Lambda>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_0087: pop + IL_0088: ret +} +"); + } + + [Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")] + public void AsStringInExpressionTrees_04() + { + var code = @" +using System; +using System.Linq.Expressions; + +Expression e = Func () => (string o) => $""""""{o.Length}"""""";"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }); + var verifier = CompileAndVerify(comp); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("", @" +{ + // Code size 137 (0x89) + .maxstack 7 + .locals init (System.Linq.Expressions.ParameterExpression V_0) + IL_0000: ldtoken ""string"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""o"" + IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" + IL_0014: stloc.0 + IL_0015: ldnull + IL_0016: ldtoken ""string string.Format(string, object)"" + IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_0020: castclass ""System.Reflection.MethodInfo"" + IL_0025: ldc.i4.2 + IL_0026: newarr ""System.Linq.Expressions.Expression"" + IL_002b: dup + IL_002c: ldc.i4.0 + IL_002d: ldstr ""{0}"" + IL_0032: ldtoken ""string"" + IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0041: stelem.ref + IL_0042: dup + IL_0043: ldc.i4.1 + IL_0044: ldloc.0 + IL_0045: ldtoken ""int string.Length.get"" + IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_004f: castclass ""System.Reflection.MethodInfo"" + IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)"" + IL_0059: ldtoken ""object"" + IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_0068: stelem.ref + IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" + IL_006e: ldc.i4.1 + IL_006f: newarr ""System.Linq.Expressions.ParameterExpression"" + IL_0074: dup + IL_0075: ldc.i4.0 + IL_0076: ldloc.0 + IL_0077: stelem.ref + IL_0078: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_007d: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty()"" + IL_0082: call ""System.Linq.Expressions.Expression>> System.Linq.Expressions.Expression.Lambda>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_0087: pop + IL_0088: ret +} +"); + } + + [Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")] + public void AsStringInExpressionTrees_05() + { + var code = @" +using System; +using System.Linq.Expressions; + +Expression> e = o => $""""""{o.Length}"""""" + $""""""literal"""""";"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }); + var verifier = CompileAndVerify(comp); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("", @" +{ + // Code size 167 (0xa7) + .maxstack 7 + .locals init (System.Linq.Expressions.ParameterExpression V_0) + IL_0000: ldtoken ""string"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""o"" + IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" + IL_0014: stloc.0 + IL_0015: ldnull + IL_0016: ldtoken ""string string.Format(string, object)"" + IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_0020: castclass ""System.Reflection.MethodInfo"" + IL_0025: ldc.i4.2 + IL_0026: newarr ""System.Linq.Expressions.Expression"" + IL_002b: dup + IL_002c: ldc.i4.0 + IL_002d: ldstr ""{0}"" + IL_0032: ldtoken ""string"" + IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0041: stelem.ref + IL_0042: dup + IL_0043: ldc.i4.1 + IL_0044: ldloc.0 + IL_0045: ldtoken ""int string.Length.get"" + IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_004f: castclass ""System.Reflection.MethodInfo"" + IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)"" + IL_0059: ldtoken ""object"" + IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_0068: stelem.ref + IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" + IL_006e: ldstr ""literal"" + IL_0073: ldtoken ""string"" + IL_0078: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_007d: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0082: ldtoken ""string string.Concat(string, string)"" + IL_0087: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_008c: castclass ""System.Reflection.MethodInfo"" + IL_0091: call ""System.Linq.Expressions.BinaryExpression System.Linq.Expressions.Expression.Add(System.Linq.Expressions.Expression, System.Linq.Expressions.Expression, System.Reflection.MethodInfo)"" + IL_0096: ldc.i4.1 + IL_0097: newarr ""System.Linq.Expressions.ParameterExpression"" + IL_009c: dup + IL_009d: ldc.i4.0 + IL_009e: ldloc.0 + IL_009f: stelem.ref + IL_00a0: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_00a5: pop + IL_00a6: ret +} +"); + } + + [Theory] + [CombinatorialData] + public void CustomHandlerUsedAsArgumentToCustomHandler(bool useBoolReturns, bool validityParameter, + [CombinatorialValues(@"$""""", @"$"""""" + +"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C.M(1, " + expression + @", " + expression + @"); + +public class C +{ + public static void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c1, [InterpolatedStringHandlerArgument(""c1"")] CustomHandler c2) => Console.WriteLine(c2.ToString()); +} + +public partial class CustomHandler +{ + private int i; + public CustomHandler(int literalLength, int formattedCount, int i" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""i:"" + i.ToString()); + this.i = i; + " + (validityParameter ? "success = true;" : "") + @" + } + public CustomHandler(int literalLength, int formattedCount, CustomHandler c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount) + { + _builder.AppendLine(""c.i:"" + c.i.ToString()); + " + (validityParameter ? "success = true;" : "") + @" + } +}"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns); + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }); + var verifier = CompileAndVerify(comp, expectedOutput: "c.i:1"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("", getIl()); + + string getIl() => (useBoolReturns, validityParameter) switch + { + (useBoolReturns: false, validityParameter: false) => @" +{ + // Code size 27 (0x1b) + .maxstack 5 + .locals init (int V_0, + CustomHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldloc.0 + IL_0006: newobj ""CustomHandler..ctor(int, int, int)"" + IL_000b: stloc.1 + IL_000c: ldloc.1 + IL_000d: ldc.i4.0 + IL_000e: ldc.i4.0 + IL_000f: ldloc.1 + IL_0010: newobj ""CustomHandler..ctor(int, int, CustomHandler)"" + IL_0015: call ""void C.M(int, CustomHandler, CustomHandler)"" + IL_001a: ret +} +", + (useBoolReturns: false, validityParameter: true) => @" +{ + // Code size 31 (0x1f) + .maxstack 6 + .locals init (int V_0, + CustomHandler V_1, + bool V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldloc.0 + IL_0006: ldloca.s V_2 + IL_0008: newobj ""CustomHandler..ctor(int, int, int, out bool)"" + IL_000d: stloc.1 + IL_000e: ldloc.1 + IL_000f: ldc.i4.0 + IL_0010: ldc.i4.0 + IL_0011: ldloc.1 + IL_0012: ldloca.s V_2 + IL_0014: newobj ""CustomHandler..ctor(int, int, CustomHandler, out bool)"" + IL_0019: call ""void C.M(int, CustomHandler, CustomHandler)"" + IL_001e: ret +} +", + (useBoolReturns: true, validityParameter: false) => @" +{ + // Code size 27 (0x1b) + .maxstack 5 + .locals init (int V_0, + CustomHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldloc.0 + IL_0006: newobj ""CustomHandler..ctor(int, int, int)"" + IL_000b: stloc.1 + IL_000c: ldloc.1 + IL_000d: ldc.i4.0 + IL_000e: ldc.i4.0 + IL_000f: ldloc.1 + IL_0010: newobj ""CustomHandler..ctor(int, int, CustomHandler)"" + IL_0015: call ""void C.M(int, CustomHandler, CustomHandler)"" + IL_001a: ret +} +", + (useBoolReturns: true, validityParameter: true) => @" +{ + // Code size 31 (0x1f) + .maxstack 6 + .locals init (int V_0, + CustomHandler V_1, + bool V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldloc.0 + IL_0006: ldloca.s V_2 + IL_0008: newobj ""CustomHandler..ctor(int, int, int, out bool)"" + IL_000d: stloc.1 + IL_000e: ldloc.1 + IL_000f: ldc.i4.0 + IL_0010: ldc.i4.0 + IL_0011: ldloc.1 + IL_0012: ldloca.s V_2 + IL_0014: newobj ""CustomHandler..ctor(int, int, CustomHandler, out bool)"" + IL_0019: call ""void C.M(int, CustomHandler, CustomHandler)"" + IL_001e: ret +} +", + }; + } + + [Fact, WorkItem(1370647, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1370647")] + public void AsFormattableString() + { + var code = @" +M($""""""{1}"""""" + $""""""literal""""""); +System.FormattableString s = $""""""{1}"""""" + $""""""literal""""""; + +void M(System.FormattableString s) +{ +} +"; + var comp = CreateCompilation(code); + comp.VerifyDiagnostics( + // (2,3): error CS1503: Argument 1: cannot convert from 'string' to 'System.FormattableString' + // M($"{1}" + $"literal"); + Diagnostic(ErrorCode.ERR_BadArgType, @"$""""""{1}"""""" + $""""""literal""""""").WithArguments("1", "string", "System.FormattableString").WithLocation(2, 3), + // (3,30): error CS0029: Cannot implicitly convert type 'string' to 'System.FormattableString' + // System.FormattableString s = $"{1}" + $"literal"; + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""""""{1}"""""" + $""""""literal""""""").WithArguments("string", "System.FormattableString").WithLocation(3, 30)); + } + + [Fact, WorkItem(1370647, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1370647")] + public void AsIFormattable() + { + var code = @" +M($""""""{1}"""""" + $""""""literal""""""); +System.IFormattable s = $""""""{1}"""""" + $""""""literal""""""; + +void M(System.IFormattable s) +{ +} +"; + var comp = CreateCompilation(code); + comp.VerifyDiagnostics( + // (2,3): error CS1503: Argument 1: cannot convert from 'string' to 'System.IFormattable' + // M($"{1}" + $"literal"); + Diagnostic(ErrorCode.ERR_BadArgType, @"$""""""{1}"""""" + $""""""literal""""""").WithArguments("1", "string", "System.IFormattable").WithLocation(2, 3), + // (3,25): error CS0029: Cannot implicitly convert type 'string' to 'System.IFormattable' + // System.IFormattable s = $"{1}" + $"literal"; + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""""""{1}"""""" + $""""""literal""""""").WithArguments("string", "System.IFormattable").WithLocation(3, 25)); + } + + [Theory] + [CombinatorialData] + public void DefiniteAssignment_01(bool useBoolReturns, bool trailingOutParameter, + [CombinatorialValues(@"$""""""{i = 1}{M(out var o)}{s = o.ToString()}""""""", @"$""""""{i = 1}"""""" + $""""""{M(out var o)}"""""" + $""""""{s = o.ToString()}""""""")] string expression) + { + var code = @" +int i; +string s; + +CustomHandler c = " + expression + @"; +_ = i.ToString(); +_ = o.ToString(); +_ = s.ToString(); + +string M(out object o) +{ + o = null; + return null; +} +"; + + var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns, includeTrailingOutConstructorParameter: trailingOutParameter); + var comp = CreateCompilation(new[] { code, customHandler }); + + if (trailingOutParameter) + { + comp.VerifyDiagnostics( + // (6,5): error CS0165: Use of unassigned local variable 'i' + // _ = i.ToString(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "i").WithArguments("i").WithLocation(6, 5), + // (7,5): error CS0165: Use of unassigned local variable 'o' + // _ = o.ToString(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "o").WithArguments("o").WithLocation(7, 5), + // (8,5): error CS0165: Use of unassigned local variable 's' + // _ = s.ToString(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(8, 5)); + } + else if (useBoolReturns) + { + comp.VerifyDiagnostics( + // (7,5): error CS0165: Use of unassigned local variable 'o' + // _ = o.ToString(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "o").WithArguments("o").WithLocation(7, 5), + // (8,5): error CS0165: Use of unassigned local variable 's' + // _ = s.ToString(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(8, 5)); + } + else + { + comp.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void DefiniteAssignment_02(bool useBoolReturns, bool trailingOutParameter, + [CombinatorialValues(@"$""""""{i = 1}""""""", @"$"""""" + +"""""" + $""""""{i = 1}""""""", @"$""""""{i = 1}"""""" + $"""""" + +""""""")] string expression) + { + var code = @" +int i; + +CustomHandler c = " + expression + @"; +_ = i.ToString(); +"; + + var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns, includeTrailingOutConstructorParameter: trailingOutParameter); + var comp = CreateCompilation(new[] { code, customHandler }); + + if (trailingOutParameter) + { + comp.VerifyDiagnostics( + // (5,5): error CS0165: Use of unassigned local variable 'i' + // _ = i.ToString(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "i").WithArguments("i")); + } + else + { + comp.VerifyDiagnostics(); + } + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void DynamicConstruction_01(string expression) + { + var code = @" +using System.Runtime.CompilerServices; +dynamic d = 1; +M(d, " + expression + @"); + +void M(dynamic d, [InterpolatedStringHandlerArgument(""d"")]CustomHandler c) {} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, dynamic d) : this() {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute }); + comp.VerifyDiagnostics( + // (4,6): error CS8953: An interpolated string handler construction cannot use dynamic. Manually construct an instance of 'CustomHandler'. + // M(d, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerCreationCannotUseDynamic, expression).WithArguments("CustomHandler").WithLocation(4, 6)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void DynamicConstruction_02(string expression) + { + var code = @" +using System.Runtime.CompilerServices; +int i = 1; +M(i, " + expression + @"); + +void M(dynamic d, [InterpolatedStringHandlerArgument(""d"")]CustomHandler c) {} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, dynamic d) : this() {} +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false); + + var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute }); + comp.VerifyDiagnostics( + // (4,6): error CS8953: An interpolated string handler construction cannot use dynamic. Manually construct an instance of 'CustomHandler'. + // M(d, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerCreationCannotUseDynamic, expression).WithArguments("CustomHandler").WithLocation(4, 6)); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void DynamicConstruction_03(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; +int i = 1; +M(i, " + expression + @"); + +void M(int i, [InterpolatedStringHandlerArgument(""i"")]CustomHandler c) {} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, dynamic d) : this(literalLength, formattedCount) + { + Console.WriteLine(""d:"" + d.ToString()); + } +} +"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false, includeOneTimeHelpers: false); + + var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var verifier = CompileAndVerify(comp, expectedOutput: "d:1"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 22 (0x16) + .maxstack 4 + .locals init (int V_0) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldloc.0 + IL_0006: box ""int"" + IL_000b: newobj ""CustomHandler..ctor(int, int, dynamic)"" + IL_0010: call ""void Program.<
$>g__M|0_0(int, CustomHandler)"" + IL_0015: ret +} +"); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void DynamicConstruction_04(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; +M(" + expression + @"); + +void M(CustomHandler c) {} + +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(dynamic literalLength, int formattedCount) + { + Console.WriteLine(""ctor""); + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var verifier = CompileAndVerify(comp, expectedOutput: "ctor"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldc.i4.0 + IL_0001: box ""int"" + IL_0006: ldc.i4.0 + IL_0007: newobj ""CustomHandler..ctor(dynamic, int)"" + IL_000c: call ""void Program.<
$>g__M|0_0(CustomHandler)"" + IL_0011: ret +} +"); + } + + [Theory] + [InlineData(@"$"""""" + +""""""")] + [InlineData(@"$"""""" + +"""""" + $"""""" + +""""""")] + public void DynamicConstruction_05(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; +M(" + expression + @"); + +void M(CustomHandler c) {} + +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) + { + Console.WriteLine(""ctor""); + } + + public CustomHandler(dynamic literalLength, int formattedCount) + { + throw null; + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var verifier = CompileAndVerify(comp, expectedOutput: "ctor"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 13 (0xd) + .maxstack 2 + IL_0000: ldc.i4.0 + IL_0001: ldc.i4.0 + IL_0002: newobj ""CustomHandler..ctor(int, int)"" + IL_0007: call ""void Program.<
$>g__M|0_0(CustomHandler)"" + IL_000c: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""Literal""""""")] + [InlineData(@"$"""""" + +"""""" + $""""""Literal""""""")] + public void DynamicConstruction_06(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; +M(" + expression + @"); + +void M(CustomHandler c) {} + +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) + { + } + + public void AppendLiteral(dynamic d) + { + Console.WriteLine(""AppendLiteral""); + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var verifier = CompileAndVerify(comp, expectedOutput: "AppendLiteral"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 28 (0x1c) + .maxstack 3 + .locals init (CustomHandler V_0) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.7 + IL_0003: ldc.i4.0 + IL_0004: call ""CustomHandler..ctor(int, int)"" + IL_0009: ldloca.s V_0 + IL_000b: ldstr ""Literal"" + IL_0010: call ""void CustomHandler.AppendLiteral(dynamic)"" + IL_0015: ldloc.0 + IL_0016: call ""void Program.<
$>g__M|0_0(CustomHandler)"" + IL_001b: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1}""""""")] + [InlineData(@"$""""""{1}"""""" + $"""""" + +""""""")] + public void DynamicConstruction_07(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; +M(" + expression + @"); + +void M(CustomHandler c) {} + +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) + { + } + + public void AppendFormatted(dynamic d) + { + Console.WriteLine(""AppendFormatted""); + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var verifier = CompileAndVerify(comp, expectedOutput: "AppendFormatted"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 29 (0x1d) + .maxstack 3 + .locals init (CustomHandler V_0) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.0 + IL_0003: ldc.i4.1 + IL_0004: call ""CustomHandler..ctor(int, int)"" + IL_0009: ldloca.s V_0 + IL_000b: ldc.i4.1 + IL_000c: box ""int"" + IL_0011: call ""void CustomHandler.AppendFormatted(dynamic)"" + IL_0016: ldloc.0 + IL_0017: call ""void Program.<
$>g__M|0_0(CustomHandler)"" + IL_001c: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""literal{d}""""""")] + [InlineData(@"$""""""literal"""""" + $""""""{d}""""""")] + public void DynamicConstruction_08(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; +dynamic d = 1; +M(" + expression + @"); + +void M(CustomHandler c) {} + +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) + { + } + + public void AppendLiteral(dynamic d) + { + Console.WriteLine(""AppendLiteral""); + } + + public void AppendFormatted(dynamic d) + { + Console.WriteLine(""AppendFormatted""); + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var verifier = CompileAndVerify(comp, expectedOutput: @" +AppendLiteral +AppendFormatted"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 128 (0x80) + .maxstack 9 + .locals init (object V_0, //d + CustomHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: box ""int"" + IL_0006: stloc.0 + IL_0007: ldloca.s V_1 + IL_0009: ldc.i4.7 + IL_000a: ldc.i4.1 + IL_000b: call ""CustomHandler..ctor(int, int)"" + IL_0010: ldloca.s V_1 + IL_0012: ldstr ""literal"" + IL_0017: call ""void CustomHandler.AppendLiteral(dynamic)"" + IL_001c: ldsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000004}> Program.<>o__0.<>p__0"" + IL_0021: brtrue.s IL_0062 + IL_0023: ldc.i4 0x100 + IL_0028: ldstr ""AppendFormatted"" + IL_002d: ldnull + IL_002e: ldtoken ""Program"" + IL_0033: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0038: ldc.i4.2 + IL_0039: newarr ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo"" + IL_003e: dup + IL_003f: ldc.i4.0 + IL_0040: ldc.i4.s 9 + IL_0042: ldnull + IL_0043: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"" + IL_0048: stelem.ref + IL_0049: dup + IL_004a: ldc.i4.1 + IL_004b: ldc.i4.0 + IL_004c: ldnull + IL_004d: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"" + IL_0052: stelem.ref + IL_0053: 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_0058: call ""System.Runtime.CompilerServices.CallSite<<>A{00000004}> System.Runtime.CompilerServices.CallSite<<>A{00000004}>.Create(System.Runtime.CompilerServices.CallSiteBinder)"" + IL_005d: stsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000004}> Program.<>o__0.<>p__0"" + IL_0062: ldsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000004}> Program.<>o__0.<>p__0"" + IL_0067: ldfld ""<>A{00000004} System.Runtime.CompilerServices.CallSite<<>A{00000004}>.Target"" + IL_006c: ldsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000004}> Program.<>o__0.<>p__0"" + IL_0071: ldloca.s V_1 + IL_0073: ldloc.0 + IL_0074: callvirt ""void <>A{00000004}.Invoke(System.Runtime.CompilerServices.CallSite, ref CustomHandler, dynamic)"" + IL_0079: ldloc.1 + IL_007a: call ""void Program.<
$>g__M|0_0(CustomHandler)"" + IL_007f: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""literal{d}""""""")] + [InlineData(@"$""""""literal"""""" + $""""""{d}""""""")] + public void DynamicConstruction_09(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; +dynamic d = 1; +M(" + expression + @"); + +void M(CustomHandler c) {} + +[InterpolatedStringHandler] +public struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount) + { + } + + public bool AppendLiteral(dynamic d) + { + Console.WriteLine(""AppendLiteral""); + return true; + } + + public bool AppendFormatted(dynamic d) + { + Console.WriteLine(""AppendFormatted""); + return true; + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var verifier = CompileAndVerify(comp, expectedOutput: @" +AppendLiteral +AppendFormatted"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 196 (0xc4) + .maxstack 11 + .locals init (object V_0, //d + CustomHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: box ""int"" + IL_0006: stloc.0 + IL_0007: ldloca.s V_1 + IL_0009: ldc.i4.7 + IL_000a: ldc.i4.1 + IL_000b: call ""CustomHandler..ctor(int, int)"" + IL_0010: ldloca.s V_1 + IL_0012: ldstr ""literal"" + IL_0017: call ""bool CustomHandler.AppendLiteral(dynamic)"" + IL_001c: brfalse IL_00bb + IL_0021: ldsfld ""System.Runtime.CompilerServices.CallSite> Program.<>o__0.<>p__1"" + IL_0026: brtrue.s IL_004c + IL_0028: ldc.i4.0 + IL_0029: ldtoken ""bool"" + IL_002e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0033: ldtoken ""Program"" + IL_0038: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_003d: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.Convert(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, System.Type, System.Type)"" + IL_0042: call ""System.Runtime.CompilerServices.CallSite> System.Runtime.CompilerServices.CallSite>.Create(System.Runtime.CompilerServices.CallSiteBinder)"" + IL_0047: stsfld ""System.Runtime.CompilerServices.CallSite> Program.<>o__0.<>p__1"" + IL_004c: ldsfld ""System.Runtime.CompilerServices.CallSite> Program.<>o__0.<>p__1"" + IL_0051: ldfld ""System.Func System.Runtime.CompilerServices.CallSite>.Target"" + IL_0056: ldsfld ""System.Runtime.CompilerServices.CallSite> Program.<>o__0.<>p__1"" + IL_005b: ldsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000004}> Program.<>o__0.<>p__0"" + IL_0060: brtrue.s IL_009d + IL_0062: ldc.i4.0 + IL_0063: ldstr ""AppendFormatted"" + IL_0068: ldnull + IL_0069: ldtoken ""Program"" + IL_006e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0073: ldc.i4.2 + IL_0074: newarr ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo"" + IL_0079: dup + IL_007a: ldc.i4.0 + IL_007b: ldc.i4.s 9 + IL_007d: ldnull + IL_007e: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"" + IL_0083: stelem.ref + IL_0084: dup + IL_0085: ldc.i4.1 + IL_0086: ldc.i4.0 + IL_0087: ldnull + IL_0088: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"" + IL_008d: stelem.ref + IL_008e: 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_0093: call ""System.Runtime.CompilerServices.CallSite<<>F{00000004}> System.Runtime.CompilerServices.CallSite<<>F{00000004}>.Create(System.Runtime.CompilerServices.CallSiteBinder)"" + IL_0098: stsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000004}> Program.<>o__0.<>p__0"" + IL_009d: ldsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000004}> Program.<>o__0.<>p__0"" + IL_00a2: ldfld ""<>F{00000004} System.Runtime.CompilerServices.CallSite<<>F{00000004}>.Target"" + IL_00a7: ldsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000004}> Program.<>o__0.<>p__0"" + IL_00ac: ldloca.s V_1 + IL_00ae: ldloc.0 + IL_00af: callvirt ""dynamic <>F{00000004}.Invoke(System.Runtime.CompilerServices.CallSite, ref CustomHandler, dynamic)"" + IL_00b4: callvirt ""bool System.Func.Invoke(System.Runtime.CompilerServices.CallSite, dynamic)"" + IL_00b9: br.s IL_00bc + IL_00bb: ldc.i4.0 + IL_00bc: pop + IL_00bd: ldloc.1 + IL_00be: call ""void Program.<
$>g__M|0_0(CustomHandler)"" + IL_00c3: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{s}""""""")] + [InlineData(@"$""""""{s}"""""" + $"""""" + +""""""")] + public void RefEscape_01(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + Span s; + + public CustomHandler(int literalLength, int formattedCount) : this() {} + + public void AppendFormatted(Span s) => this.s = s; + + public static CustomHandler M() + { + Span s = stackalloc char[10]; + return " + expression + @"; + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (17,19): error CS8352: Cannot use local 's' in this context because it may expose referenced variables outside of their declaration scope + // return $"{s}"; + Diagnostic(ErrorCode.ERR_EscapeLocal, "s").WithArguments("s").WithLocation(17, 21)); + } + + [Theory] + [InlineData(@"$""""""{s}""""""")] + [InlineData(@"$""""""{s}"""""" + $"""""" + +""""""")] + public void RefEscape_02(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + Span s; + + public CustomHandler(int literalLength, int formattedCount) : this() {} + + public void AppendFormatted(Span s) => this.s = s; + + public static ref CustomHandler M() + { + Span s = stackalloc char[10]; + return " + expression + @"; + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (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)); + } + + [Theory] + [InlineData(@"$""""""{s}""""""")] + [InlineData(@"$""""""{s}"""""" + $"""""" + +""""""")] + public void RefEscape_03(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + Span s; + + public CustomHandler(int literalLength, int formattedCount) : this() {} + + public void AppendFormatted(Span s) => this.s = s; + + public static ref CustomHandler M() + { + Span s = stackalloc char[10]; + return ref " + expression + @"; + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (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)); + } + + [Theory] + [InlineData(@"$""""""{s}""""""")] + [InlineData(@"$""""""{s}"""""" + $"""""" + +""""""")] + public void RefEscape_04(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + S1 s1; + + public CustomHandler(int literalLength, int formattedCount, ref S1 s1) : this() { this.s1 = s1; } + + public void AppendFormatted(Span s) => this.s1.s = s; + + public static void M(ref S1 s1) + { + Span s = stackalloc char[10]; + M2(ref s1, " + expression + @"); + } + + public static void M2(ref S1 s1, [InterpolatedStringHandlerArgument(""s1"")] ref CustomHandler handler) {} +} + +public ref struct S1 +{ + public Span s; +} +"; + + 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,23): error CS8352: Cannot use local 's' in this context because it may expose referenced variables outside of their declaration scope + // M2(ref s1, $"{s}"); + Diagnostic(ErrorCode.ERR_EscapeLocal, "s").WithArguments("s").WithLocation(17, 25)); + } + + [Theory] + [InlineData(@"$""""""{s1}""""""")] + [InlineData(@"$""""""{s1}"""""" + $"""""" + +""""""")] + public void RefEscape_05(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + Span s; + + public CustomHandler(int literalLength, int formattedCount, ref Span s) : this() { this.s = s; } + + public void AppendFormatted(S1 s1) => s1.s = this.s; + + public static void M(ref S1 s1) + { + Span s = stackalloc char[10]; + M2(ref s, " + expression + @"); + } + + public static void M2(ref Span s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler handler) {} +} + +public ref struct S1 +{ + public Span s; +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Theory] + [InlineData(@"$""""""{s2}""""""")] + [InlineData(@"$""""""{s2}"""""" + $"""""" + +""""""")] + public void RefEscape_06(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +Span s = stackalloc char[5]; +Span s2 = stackalloc char[10]; +s.TryWrite(" + expression + @"); + +public static class MemoryExtensions +{ + public static bool TryWrite(this Span span, [InterpolatedStringHandlerArgument(""span"")] CustomHandler builder) => true; +} + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, Span s) : this() { } + + public bool AppendFormatted(Span s) => true; +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Theory] + [InlineData(@"$""""""{s2}""""""")] + [InlineData(@"$""""""{s2}"""""" + $"""""" + +""""""")] + public void RefEscape_07(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +Span s = stackalloc char[5]; +Span s2 = stackalloc char[10]; +s.TryWrite(" + expression + @"); + +public static class MemoryExtensions +{ + public static bool TryWrite(this Span span, [InterpolatedStringHandlerArgument(""span"")] ref CustomHandler builder) => true; +} + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, Span s) : this() { } + + public bool AppendFormatted(Span s) => true; +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Fact] + public void RefEscape_08() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + Span s; + + public CustomHandler(int literalLength, int formattedCount, ref Span s) : this() { this.s = s; } + + public static CustomHandler M() + { + Span s = stackalloc char[10]; + ref CustomHandler c = ref M2(ref s, $"""""" + +""""""); + return c; + } + + public static ref CustomHandler M2(ref Span s, [InterpolatedStringHandlerArgument(""s"")] ref CustomHandler handler) + { + return ref handler; + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (16,16): error CS8352: Cannot use local 'c' in this context because it may expose referenced variables outside of their declaration scope + // return c; + Diagnostic(ErrorCode.ERR_EscapeLocal, "c").WithArguments("c").WithLocation(18, 16)); + } + + [Fact] + public void RefEscape_09() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +[InterpolatedStringHandler] +public ref struct CustomHandler +{ + Span s; + + public CustomHandler(int literalLength, int formattedCount, ref S1 s1) : this() { s1.Handler = this; } + + public static void M(ref S1 s1) + { + Span s2 = stackalloc char[10]; + M2(ref s1, $""""""{s2}""""""); + } + + public static void M2(ref S1 s1, [InterpolatedStringHandlerArgument(""s1"")] CustomHandler handler) { } + + public void AppendFormatted(Span s) { this.s = s; } +} + +public ref struct S1 +{ + public CustomHandler Handler; +} +"; + + 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,23): error CS8352: Cannot use local 's2' in this context because it may expose referenced variables outside of their declaration scope + // M2(ref s1, $"{s2}"); + Diagnostic(ErrorCode.ERR_EscapeLocal, "s2").WithArguments("s2").WithLocation(15, 25)); + } + + [Theory, WorkItem(54703, "https://github.com/dotnet/roslyn/issues/54703")] + [InlineData(@"$$""""""{ {{i}} }""""""")] + [InlineData(@"$$""""""{ """""" + $""""""{i}"""""" + $$"""""" }""""""")] + public void BracesAreEscaped_01(string expression) + { + var code = @" +int i = 1; +System.Console.WriteLine(" + expression + @");"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +{ +value:1 + }"); + + verifier.VerifyIL("", @" +{ + // Code size 56 (0x38) + .maxstack 3 + .locals init (int V_0, //i + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.4 + IL_0005: ldc.i4.1 + IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_000b: ldloca.s V_1 + IL_000d: ldstr ""{ "" + IL_0012: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_0017: ldloca.s V_1 + IL_0019: ldloc.0 + IL_001a: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_001f: ldloca.s V_1 + IL_0021: ldstr "" }"" + IL_0026: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"" + IL_002b: ldloca.s V_1 + IL_002d: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0032: call ""void System.Console.WriteLine(string)"" + IL_0037: ret +} +"); + } + + [Theory, WorkItem(54703, "https://github.com/dotnet/roslyn/issues/54703")] + [InlineData(@"$$""""""{ {{i}} }""""""")] + [InlineData(@"$$""""""{ """""" + $""""""{i}"""""" + $$"""""" }""""""")] + public void BracesAreEscaped_02(string expression) + { + var code = @" +int i = 1; +CustomHandler c = " + expression + @"; +System.Console.WriteLine(c.ToString());"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +literal:{ +value:1 +alignment:0 +format: +literal: }"); + + verifier.VerifyIL("", @" +{ + // Code size 71 (0x47) + .maxstack 4 + .locals init (int V_0, //i + CustomHandler V_1, //c + CustomHandler V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_2 + IL_0004: ldc.i4.4 + IL_0005: ldc.i4.1 + IL_0006: call ""CustomHandler..ctor(int, int)"" + IL_000b: ldloca.s V_2 + IL_000d: ldstr ""{ "" + IL_0012: call ""void CustomHandler.AppendLiteral(string)"" + IL_0017: ldloca.s V_2 + IL_0019: ldloc.0 + IL_001a: box ""int"" + IL_001f: ldc.i4.0 + IL_0020: ldnull + IL_0021: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0026: ldloca.s V_2 + IL_0028: ldstr "" }"" + IL_002d: call ""void CustomHandler.AppendLiteral(string)"" + IL_0032: ldloc.2 + IL_0033: stloc.1 + IL_0034: ldloca.s V_1 + IL_0036: constrained. ""CustomHandler"" + IL_003c: callvirt ""string object.ToString()"" + IL_0041: call ""void System.Console.WriteLine(string)"" + IL_0046: ret +} +"); + } + + [Fact] + public void InterpolatedStringsAddedUnderObjectAddition() + { + var code = @" +int i1 = 1; +int i2 = 2; +int i3 = 3; +int i4 = 4; +System.Console.WriteLine($""""""{i1}"""""" + $""""""{i2}"""""" + $""""""{i3}"""""" + i4);"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +value:2 +value:3 +4 +"); + + verifier.VerifyIL("", @" +{ + // Code size 66 (0x42) + .maxstack 3 + .locals init (int V_0, //i1 + int V_1, //i2 + int V_2, //i3 + int V_3, //i4 + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldc.i4.2 + IL_0003: stloc.1 + IL_0004: ldc.i4.3 + IL_0005: stloc.2 + IL_0006: ldc.i4.4 + IL_0007: stloc.3 + IL_0008: ldloca.s V_4 + IL_000a: ldc.i4.0 + IL_000b: ldc.i4.3 + IL_000c: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_0011: ldloca.s V_4 + IL_0013: ldloc.0 + IL_0014: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0019: ldloca.s V_4 + IL_001b: ldloc.1 + IL_001c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0021: ldloca.s V_4 + IL_0023: ldloc.2 + IL_0024: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0029: ldloca.s V_4 + IL_002b: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_0030: ldloca.s V_3 + IL_0032: call ""string int.ToString()"" + IL_0037: call ""string string.Concat(string, string)"" + IL_003c: call ""void System.Console.WriteLine(string)"" + IL_0041: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""({i1}),"""""" + $""""""[{i2}],"""""" + $$""""""{{{i3}}}""""""")] + [InlineData(@"($""""""({i1}),"""""" + $""""""[{i2}],"""""") + $$""""""{{{i3}}}""""""")] + [InlineData(@"$""""""({i1}),"""""" + ($""""""[{i2}],"""""" + $$""""""{{{i3}}}"""""")")] + public void InterpolatedStringsAddedUnderObjectAddition2(string expression) + { + var code = $@" +int i1 = 1; +int i2 = 2; +int i3 = 3; +System.Console.WriteLine({expression});"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }); + + CompileAndVerify(comp, expectedOutput: @" +( +value:1 +), +[ +value:2 +], +{ +value:3 +} +"); + } + + [Fact] + public void InterpolatedStringsAddedUnderObjectAddition3() + { + var code = @" +#nullable enable + +using System; + +try +{ + var s = string.Empty; + Console.WriteLine($""""""{s = null}{s.Length}"""""" + $"""""" + +""""""); +} +catch (NullReferenceException) +{ + Console.WriteLine(""Null reference exception caught.""); +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }); + + CompileAndVerify(comp, expectedOutput: "Null reference exception caught.").VerifyIL("", @" +{ + // Code size 65 (0x41) + .maxstack 3 + .locals init (string V_0, //s + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1) + .try + { + IL_0000: ldsfld ""string string.Empty"" + IL_0005: stloc.0 + IL_0006: ldc.i4.0 + IL_0007: ldc.i4.2 + IL_0008: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_000d: stloc.1 + IL_000e: ldloca.s V_1 + IL_0010: ldnull + IL_0011: dup + IL_0012: stloc.0 + IL_0013: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"" + IL_0018: ldloca.s V_1 + IL_001a: ldloc.0 + IL_001b: callvirt ""int string.Length.get"" + IL_0020: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0025: ldloca.s V_1 + IL_0027: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_002c: call ""void System.Console.WriteLine(string)"" + IL_0031: leave.s IL_0040 + } + catch System.NullReferenceException + { + IL_0033: pop + IL_0034: ldstr ""Null reference exception caught."" + IL_0039: call ""void System.Console.WriteLine(string)"" + IL_003e: leave.s IL_0040 + } + IL_0040: ret +} +").VerifyDiagnostics( +// (9,36): warning CS8602: Dereference of a possibly null reference. +// Console.WriteLine($"{s = null}{s.Length}" + $""); +Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(9, 38)); + } + + [Fact] + public void InterpolatedStringsAddedUnderObjectAddition_DefiniteAssignment() + { + var code = @" +object o1; +object o2; +object o3; +_ = $""""""{o1 = null}"""""" + $""""""{o2 = null}"""""" + $""""""{o3 = null}"""""" + 1; +o1.ToString(); +o2.ToString(); +o3.ToString(); +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: true) }); + comp.VerifyDiagnostics( + // (7,1): error CS0165: Use of unassigned local variable 'o2' + // o2.ToString(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "o2").WithArguments("o2").WithLocation(7, 1), + // (8,1): error CS0165: Use of unassigned local variable 'o3' + // o3.ToString(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "o3").WithArguments("o3").WithLocation(8, 1)); + } + + [Theory] + [InlineData(@"($""""""{i1}"""""" + $""""""{i2}"""""") + $""""""{i3}""""""")] + [InlineData(@"$""""""{i1}"""""" + ($""""""{i2}"""""" + $""""""{i3}"""""")")] + public void ParenthesizedAdditiveExpression_01(string expression) + { + var code = @" +int i1 = 1; +int i2 = 2; +int i3 = 3; + +CustomHandler c = " + expression + @"; +System.Console.WriteLine(c.ToString());"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:0 +format: +value:2 +alignment:0 +format: +value:3 +alignment:0 +format: +"); + + verifier.VerifyIL("", @" +{ + // Code size 82 (0x52) + .maxstack 4 + .locals init (int V_0, //i1 + int V_1, //i2 + int V_2, //i3 + CustomHandler V_3, //c + CustomHandler V_4) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldc.i4.2 + IL_0003: stloc.1 + IL_0004: ldc.i4.3 + IL_0005: stloc.2 + IL_0006: ldloca.s V_4 + IL_0008: ldc.i4.0 + IL_0009: ldc.i4.3 + IL_000a: call ""CustomHandler..ctor(int, int)"" + IL_000f: ldloca.s V_4 + IL_0011: ldloc.0 + IL_0012: box ""int"" + IL_0017: ldc.i4.0 + IL_0018: ldnull + IL_0019: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_001e: ldloca.s V_4 + IL_0020: ldloc.1 + IL_0021: box ""int"" + IL_0026: ldc.i4.0 + IL_0027: ldnull + IL_0028: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_002d: ldloca.s V_4 + IL_002f: ldloc.2 + IL_0030: box ""int"" + IL_0035: ldc.i4.0 + IL_0036: ldnull + IL_0037: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_003c: ldloc.s V_4 + IL_003e: stloc.3 + IL_003f: ldloca.s V_3 + IL_0041: constrained. ""CustomHandler"" + IL_0047: callvirt ""string object.ToString()"" + IL_004c: call ""void System.Console.WriteLine(string)"" + IL_0051: ret +}"); + } + + [Fact] + public void ParenthesizedAdditiveExpression_02() + { + var code = @" +int i1 = 1; +int i2 = 2; +int i3 = 3; +int i4 = 4; +int i5 = 5; +int i6 = 6; + +CustomHandler c = /**/((($""""""{i1}"""""" + $""""""{i2}"""""") + $""""""{i3}"""""") + ($""""""{i4}"""""" + ($""""""{i5}"""""" + $""""""{i6}""""""))) + (($""""""{i1}"""""" + ($""""""{i2}"""""" + $""""""{i3}"""""")) + (($""""""{i4}"""""" + $""""""{i5}"""""") + $""""""{i6}""""""))/**/; +System.Console.WriteLine(c.ToString());"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:0 +format: +value:2 +alignment:0 +format: +value:3 +alignment:0 +format: +value:4 +alignment:0 +format: +value:5 +alignment:0 +format: +value:6 +alignment:0 +format: +value:1 +alignment:0 +format: +value:2 +alignment:0 +format: +value:3 +alignment:0 +format: +value:4 +alignment:0 +format: +value:5 +alignment:0 +format: +value:6 +alignment:0 +format: +"); + verifier.VerifyDiagnostics(); + + VerifyOperationTreeForTest(comp, @" +IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Left: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '(($""""""{i1}"" ... """"{i6}""""""))') + Left: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '($""""""{i1}"""" ... $""""""{i3}""""""') + Left: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""""""{i1}"""""" ... $""""""{i2}""""""') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i1}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i1}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i1}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i1') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i1') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i1}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i1}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i1}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i1}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i2}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i2}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i2}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i2') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i2') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i2 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i2') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i2}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i2}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i2}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i2}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i3}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i3}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i3}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i3') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i3') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i3}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i3}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i3}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i3}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""""""{i4}"""""" ... """"""{i6}"""""")') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i4}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i4}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i4}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i4') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i4') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i4 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i4') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i4}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i4}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i4}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i4}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""""""{i5}"""""" ... $""""""{i6}""""""') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i5}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i5}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i5}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i5') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i5') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i5 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i5') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i5}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i5}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i5}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i5}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i6}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i6}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i6}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i6') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i6') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i6 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i6') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i6}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i6}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i6}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i6}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '($""""""{i1}"""" ... """"""{i6}"""""")') + Left: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""""""{i1}"""""" ... """"""{i3}"""""")') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i1}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i1}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i1}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i1') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i1') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i1}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i1}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i1}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i1}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""""""{i2}"""""" ... $""""""{i3}""""""') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i2}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i2}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i2}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i2') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i2') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i2 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i2') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i2}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i2}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i2}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i2}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i3}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i3}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i3}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i3') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i3') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i3}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i3}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i3}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i3}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '($""""""{i4}"""" ... $""""""{i6}""""""') + Left: + IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""""""{i4}"""""" ... $""""""{i5}""""""') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i4}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i4}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i4}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i4') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i4') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i4 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i4') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i4}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i4}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i4}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i4}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i5}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i5}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i5}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i5') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i5') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i5 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i5') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i5}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i5}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i5}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i5}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""""""{i6}""""""') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i6}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i6}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""""""{i1} ... """"{i6}""""""))') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i6') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i6') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILocalReferenceOperation: i6 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i6') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i6}') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i6}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i6}') + IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i6}') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) +"); + } + + [Fact] + public void ParenthesizedAdditiveExpression_03() + { + var code = @" +int i1 = 1; +int i2 = 2; +int i3 = 3; +int i4 = 4; +int i5 = 5; +int i6 = 6; + +string s = (($""""""{i1}"""""" + $""""""{i2}"""""") + $""""""{i3}"""""") + ($""""""{i4}"""""" + ($""""""{i5}"""""" + $""""""{i6}"""""")); +System.Console.WriteLine(s);"; + + var verifier = CompileAndVerify(code, expectedOutput: @"123456"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void ParenthesizedAdditiveExpression_04() + { + var code = @" +using System.Threading.Tasks; +int i1 = 2; +int i2 = 3; + +string s = $""""""{await GetInt()}"""""" + ($""""""{i1}"""""" + $""""""{i2}""""""); +System.Console.WriteLine(s); + +Task GetInt() => Task.FromResult(1); +"; + + var verifier = CompileAndVerify(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }, expectedOutput: @" +1value:2 +value:3"); + verifier.VerifyDiagnostics(); + + // Note the two DefaultInterpolatedStringHandlers in the IL here. In a future rewrite step in the LocalRewriter, we can potentially + // transform the tree to change its shape and pull out all individual Append calls in a sequence (regardless of the level of the tree) + // and combine these and other unequal tree shapes. For now, we're going with a simple solution where, if the entire binary expression + // cannot be combined, none of it is. + + verifier.VerifyIL("Program.<
$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" +{ + // Code size 244 (0xf4) + .maxstack 4 + .locals init (int V_0, + int V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.<
$>d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_004f + IL_000a: ldarg.0 + IL_000b: ldc.i4.2 + IL_000c: stfld ""int Program.<
$>d__0.5__2"" + IL_0011: ldarg.0 + IL_0012: ldc.i4.3 + IL_0013: stfld ""int Program.<
$>d__0.5__3"" + IL_0018: call ""System.Threading.Tasks.Task Program.<
$>g__GetInt|0_0()"" + IL_001d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0022: stloc.2 + IL_0023: ldloca.s V_2 + IL_0025: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_002a: brtrue.s IL_006b + IL_002c: ldarg.0 + IL_002d: ldc.i4.0 + IL_002e: dup + IL_002f: stloc.0 + IL_0030: stfld ""int Program.<
$>d__0.<>1__state"" + IL_0035: ldarg.0 + IL_0036: ldloc.2 + IL_0037: stfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_003c: ldarg.0 + IL_003d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_0042: ldloca.s V_2 + IL_0044: ldarg.0 + IL_0045: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)"" + IL_004a: leave IL_00f3 + IL_004f: ldarg.0 + IL_0050: ldfld ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_0055: stloc.2 + IL_0056: ldarg.0 + IL_0057: ldflda ""System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1"" + IL_005c: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0062: ldarg.0 + IL_0063: ldc.i4.m1 + IL_0064: dup + IL_0065: stloc.0 + IL_0066: stfld ""int Program.<
$>d__0.<>1__state"" + IL_006b: ldloca.s V_2 + IL_006d: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0072: stloc.1 + IL_0073: ldstr ""{0}"" + IL_0078: ldloc.1 + IL_0079: box ""int"" + IL_007e: call ""string string.Format(string, object)"" + IL_0083: ldc.i4.0 + IL_0084: ldc.i4.1 + IL_0085: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_008a: stloc.3 + IL_008b: ldloca.s V_3 + IL_008d: ldarg.0 + IL_008e: ldfld ""int Program.<
$>d__0.5__2"" + IL_0093: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_0098: ldloca.s V_3 + IL_009a: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_009f: ldc.i4.0 + IL_00a0: ldc.i4.1 + IL_00a1: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"" + IL_00a6: stloc.3 + IL_00a7: ldloca.s V_3 + IL_00a9: ldarg.0 + IL_00aa: ldfld ""int Program.<
$>d__0.5__3"" + IL_00af: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)"" + IL_00b4: ldloca.s V_3 + IL_00b6: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"" + IL_00bb: call ""string string.Concat(string, string, string)"" + IL_00c0: call ""void System.Console.WriteLine(string)"" + IL_00c5: leave.s IL_00e0 + } + catch System.Exception + { + IL_00c7: stloc.s V_4 + IL_00c9: ldarg.0 + IL_00ca: ldc.i4.s -2 + IL_00cc: stfld ""int Program.<
$>d__0.<>1__state"" + IL_00d1: ldarg.0 + IL_00d2: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_00d7: ldloc.s V_4 + IL_00d9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_00de: leave.s IL_00f3 + } + IL_00e0: ldarg.0 + IL_00e1: ldc.i4.s -2 + IL_00e3: stfld ""int Program.<
$>d__0.<>1__state"" + IL_00e8: ldarg.0 + IL_00e9: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder"" + IL_00ee: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00f3: ret +}"); + } + + [Fact] + public void ParenthesizedAdditiveExpression_05() + { + var code = @" +int i1 = 1; +int i2 = 2; +int i3 = 3; +int i4 = 4; +int i5 = 5; +int i6 = 6; + +string s = /**/((($""{i1}"" + $""{i2}"") + $""{i3}"") + ($""{i4}"" + ($""{i5}"" + $""{i6}""))) + (($""{i1}"" + ($""{i2}"" + $""{i3}"")) + (($""{i4}"" + $""{i5}"") + $""{i6}""))/**/; +System.Console.WriteLine(s);"; + + var comp = CreateCompilation(code); + var verifier = CompileAndVerify(comp, expectedOutput: @"123456123456"); + verifier.VerifyDiagnostics(); + + VerifyOperationTreeForTest(comp, @" +IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '((($""{i1}"" ... + $""{i6}""))') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '(($""{i1}"" + ... + $""{i6}""))') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '($""{i1}"" + ... ) + $""{i3}""') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i1}"" + $""{i2}""') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i1}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i1}') + Expression: + ILocalReferenceOperation: i1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i1') + Alignment: + null + FormatString: + null + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i2}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i2}') + Expression: + ILocalReferenceOperation: i2 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i2') + Alignment: + null + FormatString: + null + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i3}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i3}') + Expression: + ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3') + Alignment: + null + FormatString: + null + Right: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i4}"" + ( ... + $""{i6}"")') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i4}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i4}') + Expression: + ILocalReferenceOperation: i4 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i4') + Alignment: + null + FormatString: + null + Right: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i5}"" + $""{i6}""') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i5}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i5}') + Expression: + ILocalReferenceOperation: i5 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i5') + Alignment: + null + FormatString: + null + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i6}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i6}') + Expression: + ILocalReferenceOperation: i6 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i6') + Alignment: + null + FormatString: + null + Right: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '($""{i1}"" + ... + $""{i6}"")') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i1}"" + ( ... + $""{i3}"")') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i1}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i1}') + Expression: + ILocalReferenceOperation: i1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i1') + Alignment: + null + FormatString: + null + Right: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i2}"" + $""{i3}""') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i2}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i2}') + Expression: + ILocalReferenceOperation: i2 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i2') + Alignment: + null + FormatString: + null + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i3}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i3}') + Expression: + ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3') + Alignment: + null + FormatString: + null + Right: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '($""{i4}"" + ... ) + $""{i6}""') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i4}"" + $""{i5}""') + Left: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i4}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i4}') + Expression: + ILocalReferenceOperation: i4 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i4') + Alignment: + null + FormatString: + null + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i5}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i5}') + Expression: + ILocalReferenceOperation: i5 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i5') + Alignment: + null + FormatString: + null + Right: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i6}""') + Parts(1): + IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i6}') + Expression: + ILocalReferenceOperation: i6 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i6') + Alignment: + null + FormatString: + null +"); + } + + [Theory] + [InlineData(@"$""""""{1}"""""", $""""""{2}""""""")] + [InlineData(@"$""""""{1}"""""" + $"""""" + +"""""", $""""""{2}"""""" + $"""""" + +""""""")] + public void TupleDeclaration_01(string initializer) + { + var code = @" +(CustomHandler c1, CustomHandler c2) = (" + initializer + @"); +System.Console.Write(c1.ToString()); +System.Console.WriteLine(c2.ToString());"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:0 +format: +value:2 +alignment:0 +format: +"); + + verifier.VerifyIL("", @" +{ + // Code size 91 (0x5b) + .maxstack 4 + .locals init (CustomHandler V_0, //c1 + CustomHandler V_1, //c2 + CustomHandler V_2, + CustomHandler V_3) + IL_0000: ldloca.s V_3 + IL_0002: ldc.i4.0 + IL_0003: ldc.i4.1 + IL_0004: call ""CustomHandler..ctor(int, int)"" + IL_0009: ldloca.s V_3 + IL_000b: ldc.i4.1 + IL_000c: box ""int"" + IL_0011: ldc.i4.0 + IL_0012: ldnull + IL_0013: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0018: ldloc.3 + IL_0019: stloc.2 + IL_001a: ldloca.s V_3 + IL_001c: ldc.i4.0 + IL_001d: ldc.i4.1 + IL_001e: call ""CustomHandler..ctor(int, int)"" + IL_0023: ldloca.s V_3 + IL_0025: ldc.i4.2 + IL_0026: box ""int"" + IL_002b: ldc.i4.0 + IL_002c: ldnull + IL_002d: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0032: ldloc.3 + IL_0033: ldloc.2 + IL_0034: stloc.0 + IL_0035: stloc.1 + IL_0036: ldloca.s V_0 + IL_0038: constrained. ""CustomHandler"" + IL_003e: callvirt ""string object.ToString()"" + IL_0043: call ""void System.Console.Write(string)"" + IL_0048: ldloca.s V_1 + IL_004a: constrained. ""CustomHandler"" + IL_0050: callvirt ""string object.ToString()"" + IL_0055: call ""void System.Console.WriteLine(string)"" + IL_005a: ret +} +"); + } + + [Theory] + [InlineData(@"$""""""{1}"""""", $""""""{2}""""""")] + [InlineData(@"$""""""{1}"""""" + $"""""" + +"""""", $""""""{2}"""""" + $"""""" + +""""""")] + public void TupleDeclaration_02(string initializer) + { + var code = @" +(CustomHandler c1, CustomHandler c2) t = (" + initializer + @"); +System.Console.Write(t.c1.ToString()); +System.Console.WriteLine(t.c2.ToString());"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:1 +alignment:0 +format: +value:2 +alignment:0 +format: +"); + + verifier.VerifyIL("", @" +{ + // Code size 104 (0x68) + .maxstack 6 + .locals init (System.ValueTuple V_0, //t + CustomHandler V_1) + IL_0000: ldloca.s V_0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.0 + IL_0005: ldc.i4.1 + IL_0006: call ""CustomHandler..ctor(int, int)"" + IL_000b: ldloca.s V_1 + IL_000d: ldc.i4.1 + IL_000e: box ""int"" + IL_0013: ldc.i4.0 + IL_0014: ldnull + IL_0015: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_001a: ldloc.1 + IL_001b: ldloca.s V_1 + IL_001d: ldc.i4.0 + IL_001e: ldc.i4.1 + IL_001f: call ""CustomHandler..ctor(int, int)"" + IL_0024: ldloca.s V_1 + IL_0026: ldc.i4.2 + IL_0027: box ""int"" + IL_002c: ldc.i4.0 + IL_002d: ldnull + IL_002e: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0033: ldloc.1 + IL_0034: call ""System.ValueTuple..ctor(CustomHandler, CustomHandler)"" + IL_0039: ldloca.s V_0 + IL_003b: ldflda ""CustomHandler System.ValueTuple.Item1"" + IL_0040: constrained. ""CustomHandler"" + IL_0046: callvirt ""string object.ToString()"" + IL_004b: call ""void System.Console.Write(string)"" + IL_0050: ldloca.s V_0 + IL_0052: ldflda ""CustomHandler System.ValueTuple.Item2"" + IL_0057: constrained. ""CustomHandler"" + IL_005d: callvirt ""string object.ToString()"" + IL_0062: call ""void System.Console.WriteLine(string)"" + IL_0067: ret +} +"); + } + + + [Theory, WorkItem(55609, "https://github.com/dotnet/roslyn/issues/55609")] + [InlineData(@"$""""""{h1}{h2}""""""")] + [InlineData(@"$""""""{h1}"""""" + $""""""{h2}""""""")] + public void RefStructHandler_DynamicInHole(string expression) + { + var code = @" +dynamic h1 = 1; +dynamic h2 = 2; +CustomHandler c = " + expression + ";"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "ref struct", useBoolReturns: false); + + var comp = CreateCompilationWithCSharp(new[] { code, handler }); + + // Note: We don't give any errors when mixing dynamic and ref structs today. If that ever changes, we should get an + // error here. This will crash at runtime because of this. + comp.VerifyEmitDiagnostics(); + } + + [Theory] + [InlineData(@"$""""""Literal{1}""""""")] + [InlineData(@"$""""""Literal"""""" + $""""""{1}""""""")] + public void ConversionInParamsArguments(string expression) + { + var code = @" +using System; +using System.Linq; + +M(" + expression + ", " + expression + @"); + +void M(params CustomHandler[] handlers) +{ + Console.WriteLine(string.Join(Environment.NewLine, handlers.Select(h => h.ToString()))); +} +"; + + var verifier = CompileAndVerify(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, expectedOutput: @" +literal:Literal +value:1 +alignment:0 +format: + +literal:Literal +value:1 +alignment:0 +format: +"); + + verifier.VerifyDiagnostics(); + verifier.VerifyIL("", @" +{ + // Code size 100 (0x64) + .maxstack 7 + .locals init (CustomHandler V_0) + IL_0000: ldc.i4.2 + IL_0001: newarr ""CustomHandler"" + IL_0006: dup + IL_0007: ldc.i4.0 + IL_0008: ldloca.s V_0 + IL_000a: ldc.i4.7 + IL_000b: ldc.i4.1 + IL_000c: call ""CustomHandler..ctor(int, int)"" + IL_0011: ldloca.s V_0 + IL_0013: ldstr ""Literal"" + IL_0018: call ""void CustomHandler.AppendLiteral(string)"" + IL_001d: ldloca.s V_0 + IL_001f: ldc.i4.1 + IL_0020: box ""int"" + IL_0025: ldc.i4.0 + IL_0026: ldnull + IL_0027: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_002c: ldloc.0 + IL_002d: stelem ""CustomHandler"" + IL_0032: dup + IL_0033: ldc.i4.1 + IL_0034: ldloca.s V_0 + IL_0036: ldc.i4.7 + IL_0037: ldc.i4.1 + IL_0038: call ""CustomHandler..ctor(int, int)"" + IL_003d: ldloca.s V_0 + IL_003f: ldstr ""Literal"" + IL_0044: call ""void CustomHandler.AppendLiteral(string)"" + IL_0049: ldloca.s V_0 + IL_004b: ldc.i4.1 + IL_004c: box ""int"" + IL_0051: ldc.i4.0 + IL_0052: ldnull + IL_0053: call ""void CustomHandler.AppendFormatted(object, int, string)"" + IL_0058: ldloc.0 + IL_0059: stelem ""CustomHandler"" + IL_005e: call ""void Program.<
$>g__M|0_0(CustomHandler[])"" + IL_0063: ret +} +"); + } + + [Theory] + [InlineData("static")] + [InlineData("")] + public void ArgumentsOnLocalFunctions_01(string mod) + { + var code = @" +using System.Runtime.CompilerServices; + +M($"""""" + +""""""); + +" + mod + @" void M([InterpolatedStringHandlerArgument("""")] CustomHandler c) { } +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }); + comp.VerifyDiagnostics( + // (4,3): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 3), + // (6,10): error CS8944: 'M(CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument. + // void M([InterpolatedStringHandlerArgument("")] CustomHandler c) { } + Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgument("""")").WithArguments("M(CustomHandler)").WithLocation(8, 10 + mod.Length)); + } + + [Theory] + [InlineData("static")] + [InlineData("")] + public void ArgumentsOnLocalFunctions_02(string mod) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +M(1, $"""""" + +""""""); + +" + mod + @" void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c) => Console.WriteLine(c.ToString()); + +partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i) : this(literalLength, formattedCount) => _builder.Append(""i:"" + i.ToString()); +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: @"i:1"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 17 (0x11) + .maxstack 4 + .locals init (int V_0) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldloc.0 + IL_0006: newobj ""CustomHandler..ctor(int, int, int)"" + IL_000b: call ""void Program.<
$>g__M|0_0(int, CustomHandler)"" + IL_0010: ret +} +"); + } + + [Theory] + [InlineData("static")] + [InlineData("")] + public void ArgumentsOnLambdas_01(string mod) + { + var code = @" +using System.Runtime.CompilerServices; + +var a = " + mod + @" ([InterpolatedStringHandlerArgument("""")] CustomHandler c) => { }; + +a($"""""" + +""""""); +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }); + comp.VerifyDiagnostics( + // (4,12): warning CS8971: InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. + // var a = ([InterpolatedStringHandlerArgument("")] CustomHandler c) => { }; + Diagnostic(ErrorCode.WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters, @"InterpolatedStringHandlerArgument("""")").WithLocation(4, 12 + mod.Length), + // (4,12): error CS8944: 'lambda expression' is not an instance method, the receiver cannot be an interpolated string handler argument. + // var a = ([InterpolatedStringHandlerArgument("")] CustomHandler c) => { }; + Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgument("""")").WithArguments("lambda expression").WithLocation(4, 12 + mod.Length)); + } + + [Theory] + [InlineData("static")] + [InlineData("")] + public void ArgumentsOnLambdas_02(string mod) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +var a = " + mod + @" (int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c) => Console.WriteLine(c.ToString()); + +a(1, $"""""" + +""""""); + +partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i) => throw null; +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: @""); + verifier.VerifyDiagnostics( + // (5,19): warning CS8971: InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site. + // var a = (int i, [InterpolatedStringHandlerArgument("i")] CustomHandler c) => Console.WriteLine(c.ToString()); + Diagnostic(ErrorCode.WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters, @"InterpolatedStringHandlerArgument(""i"")").WithLocation(5, 19 + mod.Length)); + + verifier.VerifyIL("", @" +{ + // Code size 45 (0x2d) + .maxstack 4 + IL_0000: ldsfld ""System.Action Program.<>c.<>9__0_0"" + IL_0005: dup + IL_0006: brtrue.s IL_001f + IL_0008: pop + IL_0009: ldsfld ""Program.<>c Program.<>c.<>9"" + IL_000e: ldftn ""void Program.<>c.<
$>b__0_0(int, CustomHandler)"" + IL_0014: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_0019: dup + IL_001a: stsfld ""System.Action Program.<>c.<>9__0_0"" + IL_001f: ldc.i4.1 + IL_0020: ldc.i4.0 + IL_0021: ldc.i4.0 + IL_0022: newobj ""CustomHandler..ctor(int, int)"" + IL_0027: callvirt ""void System.Action.Invoke(int, CustomHandler)"" + IL_002c: ret +} +"); + } + + [Fact] + public void ArgumentsOnDelegateTypes_01() + { + var code = @" +using System.Runtime.CompilerServices; + +M m = null; + +m($"""""" + +""""""); + +delegate void M([InterpolatedStringHandlerArgument("""")] CustomHandler c); +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }); + comp.VerifyDiagnostics( + // (6,3): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // m($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(6, 3), + // (8,18): error CS8944: 'M.Invoke(CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument. + // delegate void M([InterpolatedStringHandlerArgument("")] CustomHandler c); + Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgument("""")").WithArguments("M.Invoke(CustomHandler)").WithLocation(10, 18)); + } + + [Fact] + public void ArgumentsOnDelegateTypes_02() + { + var vbCode = @" +Imports System.Runtime.CompilerServices +Public Delegate Sub M( c As CustomHandler) + + +Public Structure CustomHandler +End Structure +"; + + var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB }); + vbComp.VerifyDiagnostics(); + + var code = @" +M m = null; + +m($"""""" + +""""""); +"; + + var comp = CreateCompilation(code, references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (4,3): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // m($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(4, 3), + // (4,3): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments + // m($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "2").WithLocation(4, 3), + // (4,3): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments + // m($""); + Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$"""""" + +""""""").WithArguments("CustomHandler", "3").WithLocation(4, 3)); + } + + [Fact] + public void ArgumentsOnDelegateTypes_03() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +M m = (i, c) => Console.WriteLine(c.ToString()); + +m(1, $"""""" + +""""""); + +delegate void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c); + +partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int i) : this(literalLength, formattedCount) => _builder.Append(""i:"" + i.ToString()); +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: @"i:1"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 48 (0x30) + .maxstack 5 + .locals init (int V_0) + IL_0000: ldsfld ""M Program.<>c.<>9__0_0"" + IL_0005: dup + IL_0006: brtrue.s IL_001f + IL_0008: pop + IL_0009: ldsfld ""Program.<>c Program.<>c.<>9"" + IL_000e: ldftn ""void Program.<>c.<
$>b__0_0(int, CustomHandler)"" + IL_0014: newobj ""M..ctor(object, System.IntPtr)"" + IL_0019: dup + IL_001a: stsfld ""M Program.<>c.<>9__0_0"" + IL_001f: ldc.i4.1 + IL_0020: stloc.0 + IL_0021: ldloc.0 + IL_0022: ldc.i4.0 + IL_0023: ldc.i4.0 + IL_0024: ldloc.0 + IL_0025: newobj ""CustomHandler..ctor(int, int, int)"" + IL_002a: callvirt ""void M.Invoke(int, CustomHandler)"" + IL_002f: ret +} +"); + } + + [Fact] + public void HandlerConstructorWithDefaultArgument_01() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C.M($"""""" + +""""""); + +class C +{ + public static void M(CustomHandler c) => Console.WriteLine(c.ToString()); +} + +[InterpolatedStringHandler] +partial struct CustomHandler +{ + private int _i = 0; + public CustomHandler(int literalLength, int formattedCount, int i = 1) => _i = i; + public override string ToString() => _i.ToString(); +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, expectedOutput: @"1"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 14 (0xe) + .maxstack 3 + IL_0000: ldc.i4.0 + IL_0001: ldc.i4.0 + IL_0002: ldc.i4.1 + IL_0003: newobj ""CustomHandler..ctor(int, int, int)"" + IL_0008: call ""void C.M(CustomHandler)"" + IL_000d: ret +} +"); + } + + [Fact] + public void HandlerConstructorWithDefaultArgument_02() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C.M($""""""Literal""""""); + +class C +{ + public static void M(CustomHandler c) => Console.WriteLine(c.ToString()); +} + +[InterpolatedStringHandler] +partial struct CustomHandler +{ + private string _s = null; + public CustomHandler(int literalLength, int formattedCount, out bool isValid, int i = 1) { _s = i.ToString(); isValid = false; } + public void AppendLiteral(string s) => _s += s; + public override string ToString() => _s; +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, expectedOutput: @"1"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 33 (0x21) + .maxstack 4 + .locals init (CustomHandler V_0, + bool V_1) + IL_0000: ldc.i4.7 + IL_0001: ldc.i4.0 + IL_0002: ldloca.s V_1 + IL_0004: ldc.i4.1 + IL_0005: newobj ""CustomHandler..ctor(int, int, out bool, int)"" + IL_000a: stloc.0 + IL_000b: ldloc.1 + IL_000c: brfalse.s IL_001a + IL_000e: ldloca.s V_0 + IL_0010: ldstr ""Literal"" + IL_0015: call ""void CustomHandler.AppendLiteral(string)"" + IL_001a: ldloc.0 + IL_001b: call ""void C.M(CustomHandler)"" + IL_0020: ret +} +"); + } + + [Fact] + public void HandlerConstructorWithDefaultArgument_03() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C.M(1, $"""""" + +""""""); + +class C +{ + public static void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c) => Console.WriteLine(c.ToString()); +} + +[InterpolatedStringHandler] +partial struct CustomHandler +{ + private string _s = null; + public CustomHandler(int literalLength, int formattedCount, int i1, int i2 = 2) { _s = i1.ToString() + i2.ToString(); } + public void AppendLiteral(string s) => _s += s; + public override string ToString() => _s; +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, expectedOutput: @"12"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 18 (0x12) + .maxstack 5 + .locals init (int V_0) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldloc.0 + IL_0006: ldc.i4.2 + IL_0007: newobj ""CustomHandler..ctor(int, int, int, int)"" + IL_000c: call ""void C.M(int, CustomHandler)"" + IL_0011: ret +} +"); + } + + [Fact] + public void HandlerConstructorWithDefaultArgument_04() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +C.M(1, $""""""Literal""""""); + +class C +{ + public static void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c) => Console.WriteLine(c.ToString()); +} + +[InterpolatedStringHandler] +partial struct CustomHandler +{ + private string _s = null; + public CustomHandler(int literalLength, int formattedCount, int i1, out bool isValid, int i2 = 2) { _s = i1.ToString() + i2.ToString(); isValid = false; } + public void AppendLiteral(string s) => _s += s; + public override string ToString() => _s; +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, expectedOutput: @"12"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 37 (0x25) + .maxstack 6 + .locals init (int V_0, + CustomHandler V_1, + bool V_2) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.7 + IL_0004: ldc.i4.0 + IL_0005: ldloc.0 + IL_0006: ldloca.s V_2 + IL_0008: ldc.i4.2 + IL_0009: newobj ""CustomHandler..ctor(int, int, int, out bool, int)"" + IL_000e: stloc.1 + IL_000f: ldloc.2 + IL_0010: brfalse.s IL_001e + IL_0012: ldloca.s V_1 + IL_0014: ldstr ""Literal"" + IL_0019: call ""void CustomHandler.AppendLiteral(string)"" + IL_001e: ldloc.1 + IL_001f: call ""void C.M(int, CustomHandler)"" + IL_0024: ret +} +"); + } + + [Fact] + public void HandlerExtensionMethod_01() + { + var code = @" +$""""""Test"""""".M(); + +public static class StringExt +{ + public static void M(this CustomHandler handler) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }); + comp.VerifyDiagnostics( + // (2,1): error CS1929: 'string' does not contain a definition for 'M' and the best extension method overload 'StringExt.M(CustomHandler)' requires a receiver of type 'CustomHandler' + // $"Test".M(); + Diagnostic(ErrorCode.ERR_BadInstanceArgType, @"$""""""Test""""""").WithArguments("string", "M", "StringExt.M(CustomHandler)", "CustomHandler").WithLocation(2, 1)); + } + + [Fact] + public void HandlerExtensionMethod_02() + { + var code = @" +using System.Runtime.CompilerServices; + +var s = new S1(); +s.M($"""""" + +""""""); + +public struct S1 +{ + public S1() { } + public int Field = 1; +} + +public static class S1Ext +{ + public static void M(this S1 s, [InterpolatedStringHandlerArgument("""")] CustomHandler c) => throw null; +} + +partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, S1 s) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }); + comp.VerifyDiagnostics( + // (5,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually. + // s.M($""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$"""""" + +""""""").WithArguments("CustomHandler", "CustomHandler").WithLocation(5, 5), + // (14,38): error CS8944: 'S1Ext.M(S1, CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument. + // public static void M(this S1 s, [InterpolatedStringHandlerArgument("")] CustomHandler c) => throw null; + Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgument("""")").WithArguments("S1Ext.M(S1, CustomHandler)").WithLocation(17, 38)); + } + + [Fact] + public void HandlerExtensionMethod_03() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +var s = new S1(); +s.M($"""""" + +""""""); + +public struct S1 +{ + public S1() { } + public int Field = 1; +} + +public static class S1Ext +{ + public static void M(this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => Console.WriteLine(c.ToString()); +} + +partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, S1 s) : this(literalLength, formattedCount) => _builder.Append(""s.Field:"" + s.Field); +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: "s.Field:1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void HandlerExtensionMethod_04() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +var s = new S1(); +s.M($"""""" + +""""""); + +public struct S1 +{ + public S1() { } + public int Field = 1; +} + +public static class S1Ext +{ + public static void M(ref this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => Console.WriteLine(s.Field); +} + +partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, ref S1 s) : this(literalLength, formattedCount) => s.Field = 2; +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: "2"); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("", @" +{ + // Code size 25 (0x19) + .maxstack 4 + .locals init (S1 V_0, //s + S1& V_1) + IL_0000: ldloca.s V_0 + IL_0002: call ""S1..ctor()"" + IL_0007: ldloca.s V_0 + IL_0009: stloc.1 + IL_000a: ldloc.1 + IL_000b: ldc.i4.0 + IL_000c: ldc.i4.0 + IL_000d: ldloc.1 + IL_000e: newobj ""CustomHandler..ctor(int, int, ref S1)"" + IL_0013: call ""void S1Ext.M(ref S1, CustomHandler)"" + IL_0018: ret +} +"); + } + + [Fact] + public void HandlerExtensionMethod_05() + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +var s = new S1(); +s.M($"""""" + +""""""); + +public struct S1 +{ + public S1() { } + public int Field = 1; +} + +public static class S1Ext +{ + public static void M(in this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => Console.WriteLine(c.ToString()); +} + +partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, in S1 s) : this(literalLength, formattedCount) => _builder.Append(""s.Field:"" + s.Field); +} +"; + + var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: "s.Field:1"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("", @" +{ + // Code size 25 (0x19) + .maxstack 4 + .locals init (S1 V_0, //s + S1& V_1) + IL_0000: ldloca.s V_0 + IL_0002: call ""S1..ctor()"" + IL_0007: ldloca.s V_0 + IL_0009: stloc.1 + IL_000a: ldloc.1 + IL_000b: ldc.i4.0 + IL_000c: ldc.i4.0 + IL_000d: ldloc.1 + IL_000e: newobj ""CustomHandler..ctor(int, int, in S1)"" + IL_0013: call ""void S1Ext.M(in S1, CustomHandler)"" + IL_0018: ret +} +"); + } + + [Fact] + public void HandlerExtensionMethod_06() + { + var code = @" +using System.Runtime.CompilerServices; + +var s = new S1(); +s.M($"""""" + +""""""); + +public struct S1 +{ + public S1() { } + public int Field = 1; +} + +public static class S1Ext +{ + public static void M(in this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => throw null; +} + +partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, ref S1 s) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }); + comp.VerifyDiagnostics( + // (5,1): error CS1620: Argument 3 must be passed with the 'ref' keyword + // s.M($""); + Diagnostic(ErrorCode.ERR_BadArgRef, "s").WithArguments("3", "ref").WithLocation(5, 1)); + } + + [Fact] + public void HandlerExtensionMethod_07() + { + var code = @" +using System.Runtime.CompilerServices; + +var s = new S1(); +s.M($"""""" + +""""""); + +public struct S1 +{ + public S1() { } + public int Field = 1; +} + +public static class S1Ext +{ + public static void M(ref this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => throw null; +} + +partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, in S1 s) => throw null; +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }); + comp.VerifyDiagnostics( + // (5,1): error CS1615: Argument 3 may not be passed with the 'ref' keyword + // s.M($""); + Diagnostic(ErrorCode.ERR_BadArgExtraRef, "s").WithArguments("3", "ref").WithLocation(5, 1)); + } + + [Fact] + public void NoStandaloneConstructor() + { + var code = @" +using System.Runtime.CompilerServices; + +CustomHandler c = $"""""" + +""""""; + +[InterpolatedStringHandler] +struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, string s) {} +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }); + comp.VerifyDiagnostics( + // (4,19): error CS7036: There is no argument given that corresponds to the required formal parameter 's' of 'CustomHandler.CustomHandler(int, int, string)' + // CustomHandler c = $""; + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$"""""" + +""""""").WithArguments("s", "CustomHandler.CustomHandler(int, int, string)").WithLocation(4, 19), + // (4,19): error CS1615: Argument 3 may not be passed with the 'out' keyword + // CustomHandler c = $""; + Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$"""""" + +""""""").WithArguments("3", "out").WithLocation(4, 19)); + } + + [Theory] + [InlineData(@"$""""""literal{1}""""""")] + [InlineData(@"$""""""literal"""""" + $""""""{1}""""""")] + public void ReferencingThis_TopLevelObjectInitializer(string expression) + { + var code = @" +using System.Runtime.CompilerServices; + +_ = new C2 { [" + expression + @"] = { A = 1, B = 2 } }; + +public class C2 +{ + public C3 this[[InterpolatedStringHandlerArgument("""")] CustomHandler c] + { + get => new C3(); + set { } + } +} + +public class C3 +{ + public int A + { + get => 0; + set { } + } + public int B + { + get => 0; + set { } + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, C2 c) : this(literalLength, formattedCount) + { + } +} +"; + + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }); + comp.VerifyDiagnostics( + // (4,15): error CS8976: Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + // _ = new C2 { [$"literal" + $"{1}"] = { A = 1, B = 2 } }; + Diagnostic(ErrorCode.ERR_InterpolatedStringsReferencingInstanceCannotBeInObjectInitializers, expression).WithLocation(4, 15)); + } + + [Theory] + [InlineData(@"$""""""literal{1}""""""")] + [InlineData(@"$""""""literal"""""" + $""""""{1}""""""")] + public void ReferencingThis_NestedObjectInitializer(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +_ = new C1 { C2 = { [" + expression + @"] = { A = 1, B = 2 } } }; + +class C1 +{ + public C2 C2 { get => null; set { } } +} + +public class C2 +{ + public C3 this[[InterpolatedStringHandlerArgument("""")] CustomHandler c] + { + get => new C3(); + set { } + } +} + +public class C3 +{ + public int A + { + get => 0; + set { } + } + public int B + { + get => 0; + set { } + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, C2 c) : this(literalLength, formattedCount) + { + Console.WriteLine(""CustomHandler ctor""); + } +} +"; + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }); + comp.VerifyDiagnostics( + // (5,22): error CS8976: Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers. + // _ = new C1 { C2 = { [$"literal{1}"] = { A = 1, B = 2 } } }; + Diagnostic(ErrorCode.ERR_InterpolatedStringsReferencingInstanceCannotBeInObjectInitializers, expression).WithLocation(5, 22)); + } + + [Theory] + [InlineData(@"$""""""literal{1}""""""")] + [InlineData(@"$""""""literal"""""" + $""""""{1}""""""")] + public void NotReferencingThis_NestedObjectInitializer(string expression) + { + var code = @" +using System; +using System.Runtime.CompilerServices; + +_ = new C1 { C2 = { [3, " + expression + @"] = { A = 1, B = 2 } } }; + +class C1 +{ + public C2 C2 { get { Console.WriteLine(""get_C2""); return new C2(); } set { } } +} + +public class C2 +{ + public C3 this[int arg1, [InterpolatedStringHandlerArgument(""arg1"")] CustomHandler c] + { + get { Console.WriteLine(""Indexer""); return new C3(); } + set { } + } +} + +public class C3 +{ + public int A + { + get => 0; + set { } + } + public int B + { + get => 0; + set { } + } +} + +public partial struct CustomHandler +{ + public CustomHandler(int literalLength, int formattedCount, int arg1) : this(literalLength, formattedCount) + { + Console.WriteLine(""CustomHandler ctor""); + } +} +"; + CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, + expectedOutput: @" +CustomHandler ctor +get_C2 +Indexer +get_C2 +Indexer"); + } + +} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs index e27fdae67e507..1597eacea2b99 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs @@ -3184,7 +3184,11 @@ public static class IsExternalInit Assert.Equal("", constructor.GetParameters()[0].GetDocumentationCommentXml()); var property = cMember.GetMembers("I1").Single(); - Assert.Equal("", property.GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", property.GetDocumentationCommentXml()); } [Fact] @@ -3223,6 +3227,110 @@ public static class IsExternalInit var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); Assert.Equal(SymbolKind.Property, model.GetSymbolInfo(cref).Symbol!.Kind); + + var property = comp.GetMember("C.I1"); + AssertEx.Equal( +@" + Description for + +", property.GetDocumentationCommentXml()); + } + + [Fact] + public void XmlDoc_Cref_OtherMember() + { + var src = @" +/// Summary +/// Description for +public record struct C(int I1, int I2) +{ + /// Summary + /// Description for + public void M(int x) { } +} + +namespace System.Runtime.CompilerServices +{ + /// Ignored + public static class IsExternalInit + { + } +} +"; + + var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithDocumentationComments); + comp.VerifyDiagnostics( + // (4,36): warning CS1573: Parameter 'I2' has no matching param tag in the XML comment for 'C.C(int, int)' (but other parameters do) + // public record struct C(int I1, int I2) + Diagnostic(ErrorCode.WRN_MissingParamTag, "I2").WithArguments("I2", "C.C(int, int)").WithLocation(4, 36), + // (7,52): warning CS1574: XML comment has cref attribute 'x' that could not be resolved + // /// Description for + Diagnostic(ErrorCode.WRN_BadXMLRef, "x").WithArguments("x").WithLocation(7, 52) + ); + + var tree = comp.SyntaxTrees.Single(); + var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType(); + var cref = docComments.First().DescendantNodes().OfType().First().Cref; + Assert.Equal("I2", cref.ToString()); + + var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); + Assert.Equal(SymbolKind.Property, model.GetSymbolInfo(cref).Symbol!.Kind); + + var property = comp.GetMember("C.I1"); + AssertEx.Equal( +@" + Description for + +", property.GetDocumentationCommentXml()); + } + + [Fact] + public void XmlDoc_SeeAlso_InsideParamTag() + { + var src = @" +/// Summary +/// Description for something like I2 +public record struct C(int I1, int I2) +{ + /// Summary + /// Description for + public void M(int x) { } +} + +namespace System.Runtime.CompilerServices +{ + /// Ignored + public static class IsExternalInit + { + } +} +"; + + var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithDocumentationComments); + comp.VerifyDiagnostics( + // (3,77): warning CS1570: XML comment has badly formed XML -- 'End tag 'seealso' does not match the start tag 'param'.' + // /// Description for something like I2 + Diagnostic(ErrorCode.WRN_XMLParseError, "seealso").WithArguments("seealso", "param").WithLocation(3, 77), + // (3,85): warning CS1570: XML comment has badly formed XML -- 'End tag was not expected at this location.' + // /// Description for something like I2 + Diagnostic(ErrorCode.WRN_XMLParseError, "<").WithLocation(3, 85), + // (7,52): warning CS1574: XML comment has cref attribute 'x' that could not be resolved + // /// Description for + Diagnostic(ErrorCode.WRN_BadXMLRef, "x").WithArguments("x").WithLocation(7, 52) + ); + + var tree = comp.SyntaxTrees.Single(); + var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType(); + var cref = docComments.First().DescendantNodes().OfType().First().Cref; + Assert.Equal("I2", cref.ToString()); + + var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); + Assert.Equal(SymbolKind.Property, model.GetSymbolInfo(cref).Symbol!.Kind); + + var property = comp.GetMember("C.I1"); + AssertEx.Equal( +@" +", property.GetDocumentationCommentXml()); } [Fact] @@ -5738,7 +5846,6 @@ class Attr1 : System.Attribute {} Assert.Equal(1, analyzer.FireCount0); Assert.Equal(1, analyzer.FireCountRecordStructDeclarationA); - Assert.Equal(1, analyzer.FireCountRecordStructDeclarationACtor); Assert.Equal(1, analyzer.FireCount3); Assert.Equal(1, analyzer.FireCountSimpleBaseTypeI1onA); Assert.Equal(1, analyzer.FireCount5); @@ -5755,7 +5862,6 @@ private class AnalyzerActions_01_Analyzer : DiagnosticAnalyzer { public int FireCount0; public int FireCountRecordStructDeclarationA; - public int FireCountRecordStructDeclarationACtor; public int FireCount3; public int FireCountSimpleBaseTypeI1onA; public int FireCount5; @@ -5871,9 +5977,6 @@ protected void Handle6(SyntaxNodeAnalysisContext context) case "A": Interlocked.Increment(ref FireCountRecordStructDeclarationA); break; - case "A..ctor([System.Int32 X = 0])": - Interlocked.Increment(ref FireCountRecordStructDeclarationACtor); - break; default: Assert.True(false); break; @@ -6448,7 +6551,6 @@ interface I1 {} Assert.Equal(1, analyzer.FireCount0); Assert.Equal(0, analyzer.FireCountRecordStructDeclarationA); - Assert.Equal(0, analyzer.FireCountRecordStructDeclarationACtor); Assert.Equal(1, analyzer.FireCount3); Assert.Equal(0, analyzer.FireCountSimpleBaseTypeI1onA); Assert.Equal(1, analyzer.FireCount5); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index be4ff5932474b..249d3db4a97a5 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -26288,11 +26288,9 @@ class Attr3 : System.Attribute {} Assert.Equal(1, analyzer.FireCount7); Assert.Equal(1, analyzer.FireCount8); Assert.Equal(1, analyzer.FireCount9); - Assert.Equal(1, analyzer.FireCount10); Assert.Equal(1, analyzer.FireCount11); Assert.Equal(1, analyzer.FireCount12); Assert.Equal(1, analyzer.FireCount13); - Assert.Equal(1, analyzer.FireCount14); Assert.Equal(1, analyzer.FireCount15); Assert.Equal(1, analyzer.FireCount16); Assert.Equal(1, analyzer.FireCount17); @@ -26324,11 +26322,9 @@ private class AnalyzerActions_01_Analyzer : DiagnosticAnalyzer public int FireCount7; public int FireCount8; public int FireCount9; - public int FireCount10; public int FireCount11; public int FireCount12; public int FireCount13; - public int FireCount14; public int FireCount15; public int FireCount16; public int FireCount17; @@ -26490,9 +26486,6 @@ protected void Handle6(SyntaxNodeAnalysisContext context) switch (context.ContainingSymbol.ToTestDisplayString()) { - case "B..ctor([System.Int32 Y = 1])": - Interlocked.Increment(ref FireCount10); - break; case "B": Interlocked.Increment(ref FireCount11); break; @@ -26502,9 +26495,6 @@ protected void Handle6(SyntaxNodeAnalysisContext context) case "C": Interlocked.Increment(ref FireCount13); break; - case "A..ctor([System.Int32 X = 0])": - Interlocked.Increment(ref FireCount14); - break; default: Assert.True(false); break; @@ -27550,11 +27540,9 @@ interface I1 {} Assert.Equal(1, analyzer.FireCount7); Assert.Equal(0, analyzer.FireCount8); Assert.Equal(1, analyzer.FireCount9); - Assert.Equal(0, analyzer.FireCount10); Assert.Equal(0, analyzer.FireCount11); Assert.Equal(0, analyzer.FireCount12); Assert.Equal(0, analyzer.FireCount13); - Assert.Equal(0, analyzer.FireCount14); Assert.Equal(1, analyzer.FireCount15); Assert.Equal(1, analyzer.FireCount16); Assert.Equal(0, analyzer.FireCount17); @@ -28326,7 +28314,11 @@ public static class IsExternalInit Assert.Equal("", constructor.GetParameters()[0].GetDocumentationCommentXml()); var property = cMember.GetMembers("I1").Single(); - Assert.Equal("", property.GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", property.GetDocumentationCommentXml()); } [Fact, WorkItem(53912, "https://github.com/dotnet/roslyn/issues/53912")] @@ -28357,7 +28349,8 @@ public class LinkingClass var actual = GetDocumentationCommentText(comp); // the cref becomes `P:...` - var expected = (@" + var expected = +@" Test @@ -28379,6 +28372,11 @@ A sample record type A property + + + A property + + Simple class. @@ -28388,7 +28386,7 @@ Simple class. -"); +"; Assert.Equal(expected, actual); } @@ -28430,7 +28428,11 @@ public static class IsExternalInit Assert.Equal("", constructor.GetParameters()[0].GetDocumentationCommentXml()); var property = cMember.GetMembers("I1").Single(); - Assert.Equal("", property.GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", property.GetDocumentationCommentXml()); } [Fact] @@ -28718,7 +28720,11 @@ public static class IsExternalInit ", cConstructor.GetDocumentationCommentXml()); Assert.Equal("", cConstructor.GetParameters()[0].GetDocumentationCommentXml()); - Assert.Equal("", c.GetMembers("I1").Single().GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", c.GetMembers("I1").Single().GetDocumentationCommentXml()); } [Fact] @@ -28761,7 +28767,11 @@ public static class IsExternalInit ", dConstructor.GetDocumentationCommentXml()); Assert.Equal("", dConstructor.GetParameters()[0].GetDocumentationCommentXml()); - Assert.Equal("", d.GetMembers("I1").Single().GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", d.GetMembers("I1").Single().GetDocumentationCommentXml()); } [Fact] @@ -28805,7 +28815,11 @@ public static class IsExternalInit var eConstructor = e.GetMembers(".ctor").OfType().Single(); Assert.Equal("", eConstructor.GetDocumentationCommentXml()); Assert.Equal("", eConstructor.GetParameters()[0].GetDocumentationCommentXml()); - Assert.Equal("", e.GetMembers("I1").Single().GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", e.GetMembers("I1").Single().GetDocumentationCommentXml()); } [Fact] @@ -28849,7 +28863,11 @@ public static class IsExternalInit var eConstructor = e.GetMembers(".ctor").OfType().Single(); Assert.Equal("", eConstructor.GetDocumentationCommentXml()); Assert.Equal("", eConstructor.GetParameters()[0].GetDocumentationCommentXml()); - Assert.Equal("", e.GetMembers("I1").Single().GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", e.GetMembers("I1").Single().GetDocumentationCommentXml()); } [Fact] @@ -28897,7 +28915,11 @@ public static class IsExternalInit Assert.Equal(1, cConstructor.DeclaringSyntaxReferences.Count()); Assert.Equal("", cConstructor.GetDocumentationCommentXml()); Assert.Equal("", cConstructor.GetParameters()[0].GetDocumentationCommentXml()); - Assert.Equal("", c.GetMembers("I1").Single().GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", c.GetMembers("I1").Single().GetDocumentationCommentXml()); } [Fact] @@ -28944,7 +28966,11 @@ public static class IsExternalInit ", dConstructor.GetDocumentationCommentXml()); Assert.Equal("", dConstructor.GetParameters()[0].GetDocumentationCommentXml()); - Assert.Equal("", d.GetMembers("I1").Single().GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", d.GetMembers("I1").Single().GetDocumentationCommentXml()); } [Fact] @@ -28998,7 +29024,12 @@ public static class IsExternalInit ", eConstructor.GetDocumentationCommentXml()); Assert.Equal("", eConstructor.GetParameters()[0].GetDocumentationCommentXml()); - Assert.Equal("", e.GetMembers("I1").Single().GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description1 for I1 + Description2 for I1 + +", e.GetMembers("I1").Single().GetDocumentationCommentXml()); } [Fact] @@ -29100,7 +29131,11 @@ public static class IsExternalInit ", eConstructor.GetDocumentationCommentXml()); Assert.Equal("", eConstructor.GetParameters()[0].GetDocumentationCommentXml()); - Assert.Equal("", e.GetMembers("I1").Single().GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description1 for I1 + +", e.GetMembers("I1").Single().GetDocumentationCommentXml()); } [Fact] @@ -29147,7 +29182,11 @@ public static class IsExternalInit Assert.Equal("", constructor.GetParameters()[0].GetDocumentationCommentXml()); var property = cMember.GetMembers("I1").Single(); - Assert.Equal("", property.GetDocumentationCommentXml()); + AssertEx.Equal( +@" + Description for I1 + +", property.GetDocumentationCommentXml()); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs index ec4e43f9fc7ed..4e84a8101b1af 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs @@ -1850,7 +1850,8 @@ static void Main() "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: "Done").VerifyDiagnostics(); + // ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + CompileAndVerify(comp, expectedOutput: "Done", verify: Verification.FailsILVerify).VerifyDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index ebf0618a26854..91e7494d4c76c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs @@ -255,6 +255,43 @@ static void Main() Assert.Null(model.GetSymbolInfo(nullSyntax).Symbol); } + [Fact, WorkItem(18609, "https://github.com/dotnet/roslyn/issues/18609")] + public void InRawStringInterpolation() + { + string source = @" +class C +{ + static void Main() + { + System.Console.Write($""""""({default}) ({null})""""""); + } +} +"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "() ()"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var def = nodes.OfType().ElementAt(0); + Assert.Equal("default", def.ToString()); + Assert.Equal("System.Object", model.GetTypeInfo(def).Type.ToTestDisplayString()); + Assert.Equal("System.Object", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); + Assert.Null(model.GetSymbolInfo(def).Symbol); + Assert.True(model.GetConstantValue(def).HasValue); + Assert.False(model.GetConversion(def).IsNullLiteral); + Assert.True(model.GetConversion(def).IsDefaultLiteral); + + var nullSyntax = nodes.OfType().ElementAt(1); + Assert.Equal("null", nullSyntax.ToString()); + Assert.Null(model.GetTypeInfo(nullSyntax).Type); + Assert.Equal("System.Object", model.GetTypeInfo(nullSyntax).ConvertedType.ToTestDisplayString()); + Assert.Null(model.GetSymbolInfo(nullSyntax).Symbol); + } + [Fact, WorkItem(35684, "https://github.com/dotnet/roslyn/issues/35684")] [WorkItem(40791, "https://github.com/dotnet/roslyn/issues/40791")] public void ComparisonWithGenericType_Unconstrained() @@ -1885,7 +1922,7 @@ static void Main() "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); - CompileAndVerify(comp, expectedOutput: "123: True"); + CompileAndVerify(comp, expectedOutput: "123: True", verify: Verification.FailsILVerify); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs index f5a4253b4995d..38f818445ecd8 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs @@ -6374,8 +6374,6 @@ public void AnalyzerActions_01() Assert.Equal(0, analyzer.FireCount2); Assert.Equal(1, analyzer.FireCount3); Assert.Equal(0, analyzer.FireCount4); - Assert.Equal(1, analyzer.FireCount5); - Assert.Equal(0, analyzer.FireCount6); var text2 = @"System.Console.WriteLine(2);"; @@ -6387,8 +6385,6 @@ public void AnalyzerActions_01() Assert.Equal(1, analyzer.FireCount2); Assert.Equal(1, analyzer.FireCount3); Assert.Equal(1, analyzer.FireCount4); - Assert.Equal(1, analyzer.FireCount5); - Assert.Equal(1, analyzer.FireCount6); } private class AnalyzerActions_01_Analyzer : DiagnosticAnalyzer @@ -6397,8 +6393,6 @@ private class AnalyzerActions_01_Analyzer : DiagnosticAnalyzer public int FireCount2; public int FireCount3; public int FireCount4; - public int FireCount5; - public int FireCount6; private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test"); @@ -6451,10 +6445,10 @@ private void Handle2(SyntaxNodeAnalysisContext context) switch (unit.ToString()) { case "System.Console.WriteLine(1);": - Interlocked.Increment(ref context.ContainingSymbol.Kind == SymbolKind.Namespace ? ref FireCount5 : ref FireCount3); + Interlocked.Increment(ref FireCount3); break; case "System.Console.WriteLine(2);": - Interlocked.Increment(ref context.ContainingSymbol.Kind == SymbolKind.Namespace ? ref FireCount6 : ref FireCount4); + Interlocked.Increment(ref FireCount4); break; default: Assert.True(false); @@ -6463,16 +6457,6 @@ private void Handle2(SyntaxNodeAnalysisContext context) switch (context.ContainingSymbol.ToTestDisplayString()) { - case "": - Assert.Same(unit.SyntaxTree, context.ContainingSymbol.DeclaringSyntaxReferences.Single().SyntaxTree); - Assert.True(syntaxTreeModel.TestOnlyMemberModels.ContainsKey(unit)); - - MemberSemanticModel mm = syntaxTreeModel.TestOnlyMemberModels[unit]; - - Assert.False(mm.TestOnlyTryGetBoundNodesFromMap(unit).IsDefaultOrEmpty); - - Assert.Same(mm, syntaxTreeModel.GetMemberModel(unit)); - break; case "": break; default: @@ -7022,7 +7006,6 @@ void M() Assert.Equal(1, analyzer.FireCount1); Assert.Equal(1, analyzer.FireCount2); Assert.Equal(1, analyzer.FireCount3); - Assert.Equal(1, analyzer.FireCount4); analyzer = new AnalyzerActions_09_Analyzer(); comp = CreateCompilation(new[] { text1, text2 }, options: TestOptions.DebugExe, parseOptions: DefaultParseOptions); @@ -7030,8 +7013,7 @@ void M() Assert.Equal(1, analyzer.FireCount1); Assert.Equal(1, analyzer.FireCount2); - Assert.Equal(1, analyzer.FireCount3); - Assert.Equal(2, analyzer.FireCount4); + Assert.Equal(2, analyzer.FireCount3); } private class AnalyzerActions_09_Analyzer : DiagnosticAnalyzer @@ -7039,7 +7021,6 @@ private class AnalyzerActions_09_Analyzer : DiagnosticAnalyzer public int FireCount1; public int FireCount2; public int FireCount3; - public int FireCount4; private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test"); @@ -7095,20 +7076,8 @@ private void Handle2(SyntaxNodeAnalysisContext context) switch (context.ContainingSymbol.ToTestDisplayString()) { - case @"": - Interlocked.Increment(ref FireCount3); - - Assert.True(syntaxTreeModel.TestOnlyMemberModels.ContainsKey(node)); - - MemberSemanticModel mm = syntaxTreeModel.TestOnlyMemberModels[node]; - - Assert.False(mm.TestOnlyTryGetBoundNodesFromMap(node).IsDefaultOrEmpty); - - Assert.Same(mm, syntaxTreeModel.GetMemberModel(node)); - break; - case "": - Interlocked.Increment(ref FireCount4); + Interlocked.Increment(ref FireCount3); break; default: @@ -7151,7 +7120,6 @@ public MyAttribute(int x) {} Assert.Equal(1, analyzer.FireCount2); Assert.Equal(1, analyzer.FireCount3); Assert.Equal(1, analyzer.FireCount4); - Assert.Equal(1, analyzer.FireCount5); analyzer = new AnalyzerActions_10_Analyzer(); comp = CreateCompilation(new[] { text1, text2, text3 }, options: TestOptions.DebugExe, parseOptions: DefaultParseOptions); @@ -7160,8 +7128,7 @@ public MyAttribute(int x) {} Assert.Equal(1, analyzer.FireCount1); Assert.Equal(1, analyzer.FireCount2); Assert.Equal(1, analyzer.FireCount3); - Assert.Equal(1, analyzer.FireCount4); - Assert.Equal(3, analyzer.FireCount5); + Assert.Equal(3, analyzer.FireCount4); } private class AnalyzerActions_10_Analyzer : DiagnosticAnalyzer @@ -7170,7 +7137,6 @@ private class AnalyzerActions_10_Analyzer : DiagnosticAnalyzer public int FireCount2; public int FireCount3; public int FireCount4; - public int FireCount5; private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test"); @@ -7215,12 +7181,8 @@ private void Handle2(SyntaxNodeAnalysisContext context) { switch (context.ContainingSymbol.ToTestDisplayString()) { - case @"": - Interlocked.Increment(ref FireCount4); - break; - case @"": - Interlocked.Increment(ref FireCount5); + Interlocked.Increment(ref FireCount4); break; default: diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs index 44a2528b87e2b..de70e1f4ea21f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Linq; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -2310,6 +2311,13 @@ static C() } "; var comp = CreateCompilation(new[] { source1, source2 }, options: WithNullableEnable()); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[0], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify(); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[1], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify(); + comp.VerifyDiagnostics( // (4,28): warning CS0414: The field 'C.s1' is assigned but its value is never used // static readonly string s1; @@ -2333,12 +2341,124 @@ partial class C } "; var comp = CreateCompilation(new[] { source1, source2 }, options: WithNullableEnable()); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[0], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify( + // (4,37): warning CS8602: Dereference of a possibly null reference. + // static readonly string Field1 = Field2.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Field2").WithLocation(4, 37)); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[1], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify(); + comp.VerifyDiagnostics( // (4,37): warning CS8602: Dereference of a possibly null reference. // static readonly string Field1 = Field2.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Field2").WithLocation(4, 37)); } + [Fact] + public void StaticInitializers_MultipleFiles_03() + { + var source1 = @" +public partial class Class1 +{ + public static readonly string Value1; + + static Class1 () + { + Value1 = string.Empty; + Value2 = string.Empty; + } +} +"; + var source2 = @" +public partial class Class1 +{ + public static readonly string Value2; +} +"; + var comp = CreateCompilation(new[] { source1, source2 }, options: WithNullableEnable()); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[0], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify(); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[1], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify(); + + comp.VerifyDiagnostics(); + } + + [Fact] + public void StaticInitializers_MultipleFiles_04() + { + var source1 = @" +public partial class Class1 +{ + public static readonly string Value1; // 1 +} +"; + var source2 = @" +public partial class Class1 +{ + public static readonly string Value2; // 2 +} +"; + var comp = CreateCompilation(new[] { source1, source2 }, options: WithNullableEnable()); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[0], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify( + // (4,35): warning CS8618: Non-nullable field 'Value1' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public static readonly string Value1; // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Value1").WithArguments("field", "Value1").WithLocation(4, 35)); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[1], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify( + // (4,35): warning CS8618: Non-nullable field 'Value2' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public static readonly string Value2; // 2 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Value2").WithArguments("field", "Value2").WithLocation(4, 35)); + + comp.VerifyDiagnostics( + // (4,35): warning CS8618: Non-nullable field 'Value1' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public static readonly string Value1; // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Value1").WithArguments("field", "Value1").WithLocation(4, 35), + // (4,35): warning CS8618: Non-nullable field 'Value2' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public static readonly string Value2; // 2 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Value2").WithArguments("field", "Value2").WithLocation(4, 35)); + } + + [Fact] + public void StaticInitializers_MultipleFiles_05() + { + var source1 = @" +public partial class Class1 +{ + public static readonly string Value1 = ""a""; +} +"; + var source2 = @" +public partial class Class1 +{ + public static readonly string Value2; // 1 +} +"; + var comp = CreateCompilation(new[] { source1, source2 }, options: WithNullableEnable()); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[0], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify(); + + comp.GetDiagnosticsForSyntaxTree(CompilationStage.Compile, comp.SyntaxTrees[1], filterSpanWithinTree: null, includeEarlierStages: true) + .Verify( + // (4,35): warning CS8618: Non-nullable field 'Value2' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public static readonly string Value2; // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Value2").WithArguments("field", "Value2").WithLocation(4, 35)); + + comp.VerifyDiagnostics( + // (4,35): warning CS8618: Non-nullable field 'Value2' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public static readonly string Value2; // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Value2").WithArguments("field", "Value2").WithLocation(4, 35)); + } + [Fact] [WorkItem(1090263, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems/edit/1090263")] public void PropertyNoGetter() @@ -2456,5 +2576,49 @@ public class C Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 49) ); } + + [Fact] + [WorkItem(58073, "https://github.com/dotnet/roslyn/issues/58073")] + public void DiagnosticAdditionalLocations_SquiggleConstructor() + { + var source = +@" +public class C +{ + public C() { } + + public string S { get; } +}"; + var comp = CreateCompilation(source, options: WithNullableEnable()); + comp.VerifyDiagnostics( + // (4,12): warning CS8618: Non-nullable property 'S' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public C() { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("property", "S").WithLocation(4, 12)); + + var property = comp.GetTypeByMetadataName("C").GetMember("S"); + var actualAdditionalLocations = comp.GetDiagnostics().Single().AdditionalLocations; + Assert.Equal(property.Locations.Single(), actualAdditionalLocations.Single()); + } + + [Fact] + [WorkItem(58073, "https://github.com/dotnet/roslyn/issues/58073")] + public void DiagnosticAdditionalLocations_SquiggleProperty() + { + var source = +@" +public class C +{ + public string S { get; } +}"; + var comp = CreateCompilation(source, options: WithNullableEnable()); + comp.VerifyDiagnostics( + // (4,19): warning CS8618: Non-nullable property 'S' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public string S { get; } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("property", "S").WithLocation(4, 19)); + + var property = comp.GetTypeByMetadataName("C").GetMember("S"); + var actualAdditionalLocations = comp.GetDiagnostics().Single().AdditionalLocations; + Assert.Equal(property.Locations.Single(), actualAdditionalLocations.Single()); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UseSiteErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UseSiteErrorTests.cs index eff9158c26ef9..b24263d3f4952 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UseSiteErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UseSiteErrorTests.cs @@ -2367,7 +2367,8 @@ interface I2 // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1) ); - CompileAndVerify(compilation5); + // ILVerify: no corlib + CompileAndVerify(compilation5, verify: Verification.FailsILVerify); Assert.Equal(TypeKind.Struct, compilation5.GetTypeByMetadataName("A").TypeKind); Assert.Equal(TypeKind.Enum, compilation5.GetTypeByMetadataName("B").TypeKind); diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index 083731a461eb5..e191d0b9fbcda 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -847,7 +847,7 @@ class C compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); - var options = new CompilerAnalyzerConfigOptionsProvider(ImmutableDictionary.Empty, new CompilerAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("a", "abc").Add("b", "def"))); + var options = new CompilerAnalyzerConfigOptionsProvider(ImmutableDictionary.Empty, new DictionaryAnalyzerConfigOptions(ImmutableDictionary.Empty.Add("a", "abc").Add("b", "def"))); AnalyzerConfigOptionsProvider? passedIn = null; var testGenerator = new CallbackGenerator( @@ -2190,7 +2190,7 @@ class C { } var builder = ImmutableDictionary.Empty.ToBuilder(); builder.Add("test", "value1"); - var optionsProvider = new CompilerAnalyzerConfigOptionsProvider(ImmutableDictionary.Empty, new CompilerAnalyzerConfigOptions(builder.ToImmutable())); + var optionsProvider = new CompilerAnalyzerConfigOptionsProvider(ImmutableDictionary.Empty, new DictionaryAnalyzerConfigOptions(builder.ToImmutable())); // run the generator once, and check it was passed the configs GeneratorDriver driver = CSharpGeneratorDriver.Create(new ISourceGenerator[] { generator }, parseOptions: parseOptions, optionsProvider: optionsProvider, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); @@ -2227,7 +2227,7 @@ class C { } // now update the config builder.Clear(); builder.Add("test", "value2"); - var newOptionsProvider = optionsProvider.WithGlobalOptions(new CompilerAnalyzerConfigOptions(builder.ToImmutable())); + var newOptionsProvider = optionsProvider.WithGlobalOptions(new DictionaryAnalyzerConfigOptions(builder.ToImmutable())); driver = driver.WithUpdatedAnalyzerConfigOptions(newOptionsProvider); // check we ran @@ -2806,5 +2806,43 @@ class C { } driver = driver.RunGenerators(compilation); Assert.Single(referenceList, modifiedRef.Display); } + + [ConditionalFact(typeof(NoIOperationValidation))] + [WorkItem(59190, "https://github.com/dotnet/roslyn/issues/59190")] + public void LongBinaryExpression() + { + var source = @" +class C { +public static readonly string F = ""a"" +"; + + for (int i = 0; i < 7000; i++) + { + source += @" + ""a"" +"; + } + + source += @"; +} +"; + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + compilation.VerifyDiagnostics(); + Assert.Single(compilation.SyntaxTrees); + + var generator = new PipelineCallbackGenerator(ctx => + { + ctx.RegisterSourceOutput(ctx.SyntaxProvider.CreateSyntaxProvider((node, ct) => node is ClassDeclarationSyntax c, (context, ct) => context.Node).WithTrackingName("Syntax"), (context, ct) => { }); + ctx.RegisterSourceOutput(ctx.CompilationProvider, (context, ct) => { }); + ctx.RegisterSourceOutput(ctx.AnalyzerConfigOptionsProvider, (context, ct) => { }); + ctx.RegisterSourceOutput(ctx.ParseOptionsProvider, (context, ct) => { }); + ctx.RegisterSourceOutput(ctx.AdditionalTextsProvider, (context, ct) => { }); + ctx.RegisterImplementationSourceOutput(ctx.MetadataReferencesProvider, (context, ct) => { }); + }); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: parseOptions, additionalTexts: new[] { new InMemoryAdditionalText("text.txt", "") }, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + driver = driver.RunGenerators(compilation); + driver.GetRunResult(); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs index 044a1cb6eae36..363c72171b1f4 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs @@ -325,9 +325,6 @@ public void Driver_Table_Compacts_State_Tables_And_Drops_Steps_When_Made_Immutab DriverStateTable.Builder builder2 = GetBuilder(driverStateTable, trackIncrementalGeneratorSteps: true); builder2.GetLatestStateTableForNode(callbackNode); - // table persisted in driverStateTable does not have any steps - Assert.False(driverStateTable.GetStateTableOrEmpty(callbackNode).HasTrackedSteps); - // table returned from the first instance was compacted by the builder Assert.NotNull(passedIn); AssertTableEntries(passedIn!, new[] { (1, EntryState.Cached, 0), (2, EntryState.Cached, 1), (3, EntryState.Cached, 2), (5, EntryState.Cached, 0), (6, EntryState.Cached, 1) }); @@ -955,11 +952,12 @@ private DriverStateTable.Builder GetBuilder(DriverStateTable previous, bool trac ImmutableArray.Empty, ImmutableArray.Empty, previous, + SyntaxStore.Empty, disabledOutputs: IncrementalGeneratorOutputKind.None, runtime: TimeSpan.Zero, trackIncrementalGeneratorSteps: trackIncrementalGeneratorSteps); - return new DriverStateTable.Builder(c, state, ImmutableArray.Empty); + return new DriverStateTable.Builder(c, state, SyntaxStore.Empty.ToBuilder(c, ImmutableArray.Empty, trackIncrementalGeneratorSteps, cancellationToken: default)); } private class CallbackNode : IIncrementalGeneratorNode diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/SyntaxAwareGeneratorTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/SyntaxAwareGeneratorTests.cs index ce8de0cfc2d46..0fd4decbb606f 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/SyntaxAwareGeneratorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/SyntaxAwareGeneratorTests.cs @@ -946,16 +946,26 @@ class C Compilation compilation = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); + List syntaxFilterVisited = new(); var testGenerator = new PipelineCallbackGenerator(context => { - var source = context.SyntaxProvider.CreateSyntaxProvider((c, _) => c is FieldDeclarationSyntax fds, (c, _) => ((FieldDeclarationSyntax)c.Node).Declaration.Variables[0].Identifier.ValueText).WithTrackingName("Fields"); + var source = context.SyntaxProvider.CreateSyntaxProvider((c, _) => + { + if (c is FieldDeclarationSyntax fds) + { + syntaxFilterVisited.Add(fds.Declaration.Variables[0].Identifier.ValueText); + return true; + } + return false; + }, (c, _) => ((FieldDeclarationSyntax)c.Node).Declaration.Variables[0].Identifier.ValueText); context.RegisterSourceOutput(source, (spc, fieldName) => { spc.AddSource(fieldName, ""); }); }); - GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { new IncrementalGeneratorWrapper(testGenerator) }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + // Don't enable incremental tracking here as incremental tracking disables the "unchanged compilation implies unchanged syntax trees" optimization. + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { new IncrementalGeneratorWrapper(testGenerator) }, parseOptions: parseOptions); driver = driver.RunGenerators(compilation); var results = driver.GetRunResult(); @@ -964,14 +974,9 @@ class C Assert.EndsWith("fieldA.cs", results.GeneratedTrees[0].FilePath); Assert.EndsWith("fieldB.cs", results.GeneratedTrees[1].FilePath); Assert.EndsWith("fieldC.cs", results.GeneratedTrees[2].FilePath); - Assert.Collection(results.Results[0].TrackedSteps["Fields"], - step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldA", IncrementalStepRunReason.New), output)), - step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldB", IncrementalStepRunReason.New), output)), - step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldC", IncrementalStepRunReason.New), output))); + Assert.Equal(new[] { "fieldA", "fieldB", "fieldC" }, syntaxFilterVisited); + syntaxFilterVisited.Clear(); // run again on the *same* compilation driver = driver.RunGenerators(compilation); results = driver.GetRunResult(); @@ -980,13 +985,7 @@ class C Assert.EndsWith("fieldA.cs", results.GeneratedTrees[0].FilePath); Assert.EndsWith("fieldB.cs", results.GeneratedTrees[1].FilePath); Assert.EndsWith("fieldC.cs", results.GeneratedTrees[2].FilePath); - Assert.Collection(results.Results[0].TrackedSteps["Fields"], - step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldA", IncrementalStepRunReason.Cached), output)), - step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldB", IncrementalStepRunReason.Cached), output)), - step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldC", IncrementalStepRunReason.Cached), output))); + Assert.Empty(syntaxFilterVisited); // now change the compilation, but don't change the syntax trees compilation = compilation.WithAssemblyName("newCompilation"); @@ -997,13 +996,7 @@ class C Assert.EndsWith("fieldA.cs", results.GeneratedTrees[0].FilePath); Assert.EndsWith("fieldB.cs", results.GeneratedTrees[1].FilePath); Assert.EndsWith("fieldC.cs", results.GeneratedTrees[2].FilePath); - Assert.Collection(results.Results[0].TrackedSteps["Fields"], - step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldA", IncrementalStepRunReason.Cached), output)), - step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldB", IncrementalStepRunReason.Cached), output)), - step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldC", IncrementalStepRunReason.Cached), output))); + Assert.Equal(new[] { "fieldA", "fieldB", "fieldC" }, syntaxFilterVisited); } [Fact] @@ -1070,11 +1063,11 @@ class D Assert.EndsWith("fieldE.cs", results.GeneratedTrees[4].FilePath); Assert.Collection(results.Results[0].TrackedSteps["Fields"], step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldA", IncrementalStepRunReason.Cached), output)), + output => Assert.Equal(("fieldA", IncrementalStepRunReason.Unchanged), output)), step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldB", IncrementalStepRunReason.Cached), output)), + output => Assert.Equal(("fieldB", IncrementalStepRunReason.Unchanged), output)), step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldC", IncrementalStepRunReason.Cached), output)), + output => Assert.Equal(("fieldC", IncrementalStepRunReason.Unchanged), output)), step => Assert.Collection(step.Outputs, output => Assert.Equal(("fieldD", IncrementalStepRunReason.New), output)), step => Assert.Collection(step.Outputs, @@ -1149,11 +1142,11 @@ class D Assert.EndsWith("fieldC.cs", results.GeneratedTrees[2].FilePath); Assert.Collection(results.Results[0].TrackedSteps["Fields"], step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldA", IncrementalStepRunReason.Cached), output)), + output => Assert.Equal(("fieldA", IncrementalStepRunReason.Unchanged), output)), step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldB", IncrementalStepRunReason.Cached), output)), + output => Assert.Equal(("fieldB", IncrementalStepRunReason.Unchanged), output)), step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldC", IncrementalStepRunReason.Cached), output)), + output => Assert.Equal(("fieldC", IncrementalStepRunReason.Unchanged), output)), step => Assert.Collection(step.Outputs, output => Assert.Equal(("fieldD", IncrementalStepRunReason.Removed), output)), step => Assert.Collection(step.Outputs, @@ -1273,6 +1266,7 @@ class F }", parseOptions); compilation = compilation.ReplaceSyntaxTree(firstTree, newTree); + fieldsCalledFor.Clear(); // now re-run the drivers driver = driver.RunGenerators(compilation); results = driver.GetRunResult(); @@ -1287,9 +1281,83 @@ class F step => Assert.Collection(step.Outputs, output => Assert.Equal(("fieldD", IncrementalStepRunReason.Modified), output)), step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldB", IncrementalStepRunReason.Cached), output)), + output => Assert.Equal(("fieldB", IncrementalStepRunReason.Unchanged), output)), step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldC", IncrementalStepRunReason.Cached), output))); + output => Assert.Equal(("fieldC", IncrementalStepRunReason.Unchanged), output))); + Assert.Equal("fieldD", Assert.Single(fieldsCalledFor)); + } + + [Fact] + public void IncrementalGenerator_With_Syntax_Filter_Doesnt_Run_When_Compilation_Is_Unchanged() + { + var source1 = @" +#pragma warning disable CS0414 +class C +{ + string fieldA = null; +}"; + var source2 = @" +#pragma warning disable CS0414 +class D +{ + string fieldB = null; +}"; + var source3 = @" +#pragma warning disable CS0414 +class E +{ + string fieldC = null; +}"; + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll, parseOptions: parseOptions); + compilation.VerifyDiagnostics(); + + List fieldsCalledFor = new List(); + var testGenerator = new PipelineCallbackGenerator(context => + { + var source = context.SyntaxProvider.CreateSyntaxProvider((c, _) => c is FieldDeclarationSyntax fds, (c, _) => ((FieldDeclarationSyntax)c.Node).Declaration.Variables[0].Identifier.ValueText).WithTrackingName("Fields"); + context.RegisterSourceOutput(source, (spc, fieldName) => + { + spc.AddSource(fieldName, ""); + fieldsCalledFor.Add(fieldName); + }); + }); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { new IncrementalGeneratorWrapper(testGenerator) }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: false)); + driver = driver.RunGenerators(compilation); + + var results = driver.GetRunResult(); + Assert.Empty(results.Diagnostics); + Assert.EndsWith("fieldA.cs", results.GeneratedTrees[0].FilePath); + Assert.EndsWith("fieldB.cs", results.GeneratedTrees[1].FilePath); + Assert.EndsWith("fieldC.cs", results.GeneratedTrees[2].FilePath); + Assert.Equal(new[] { "fieldA", "fieldB", "fieldC" }, fieldsCalledFor); + + // now re-run the drivers with the same compilation + fieldsCalledFor.Clear(); + driver = driver.RunGenerators(compilation); + results = driver.GetRunResult(); + Assert.Empty(results.Diagnostics); + Assert.Equal(3, results.GeneratedTrees.Length); + + // we produced the expected modified sources, but didn't call for any of the trees + Assert.EndsWith("fieldA.cs", results.GeneratedTrees[0].FilePath); + Assert.EndsWith("fieldB.cs", results.GeneratedTrees[1].FilePath); + Assert.EndsWith("fieldC.cs", results.GeneratedTrees[2].FilePath); + Assert.Empty(fieldsCalledFor); + + // now re-run the drivers with the same compilation again to ensure we cached the trees correctly + fieldsCalledFor.Clear(); + driver = driver.RunGenerators(compilation); + results = driver.GetRunResult(); + Assert.Empty(results.Diagnostics); + Assert.Equal(3, results.GeneratedTrees.Length); + + // we produced the expected modified sources, but didn't call for any of the trees + Assert.EndsWith("fieldA.cs", results.GeneratedTrees[0].FilePath); + Assert.EndsWith("fieldB.cs", results.GeneratedTrees[1].FilePath); + Assert.EndsWith("fieldC.cs", results.GeneratedTrees[2].FilePath); + Assert.Empty(fieldsCalledFor); } [Fact] @@ -1330,7 +1398,8 @@ class E } return false; }, - (c, _) => ((FieldDeclarationSyntax)c.Node).Declaration.Variables[0].Identifier.ValueText).WithTrackingName("Fields"); + (c, _) => ((FieldDeclarationSyntax)c.Node).Declaration.Variables[0].Identifier.ValueText).WithTrackingName("Syntax") + .Select((s, ct) => s).WithTrackingName("Fields"); context.RegisterSourceOutput(source, (spc, fieldName) => { @@ -1338,7 +1407,10 @@ class E }); }); - GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { new IncrementalGeneratorWrapper(testGenerator) }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + GeneratorDriver driver = CSharpGeneratorDriver.Create( + new[] { new IncrementalGeneratorWrapper(testGenerator) }, + parseOptions: parseOptions, + driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); driver = driver.RunGenerators(compilation); var results = driver.GetRunResult(); @@ -1367,7 +1439,8 @@ class E .ReplaceSyntaxTree(lastTree, firstTree) .ReplaceSyntaxTree(dummyTree, lastTree); - // now re-run the drivers and confirm we didn't actually run + // now re-run the drivers and confirm we didn't actually run the node selector for any nodes. + // Verify that we still ran the transform. syntaxFieldsCalledFor.Clear(); driver = driver.RunGenerators(compilation); results = driver.GetRunResult(); @@ -1376,6 +1449,13 @@ class E Assert.EndsWith("fieldA.cs", results.GeneratedTrees[0].FilePath); Assert.EndsWith("fieldB.cs", results.GeneratedTrees[1].FilePath); Assert.EndsWith("fieldC.cs", results.GeneratedTrees[2].FilePath); + Assert.Collection(results.Results[0].TrackedSteps["Syntax"], + step => Assert.Collection(step.Outputs, + output => Assert.Equal(("fieldA", IncrementalStepRunReason.Unchanged), output)), + step => Assert.Collection(step.Outputs, + output => Assert.Equal(("fieldB", IncrementalStepRunReason.Unchanged), output)), + step => Assert.Collection(step.Outputs, + output => Assert.Equal(("fieldC", IncrementalStepRunReason.Unchanged), output))); Assert.Collection(results.Results[0].TrackedSteps["Fields"], step => Assert.Collection(step.Outputs, output => Assert.Equal(("fieldA", IncrementalStepRunReason.Cached), output)), @@ -1393,8 +1473,8 @@ class E .ReplaceSyntaxTree(lastTree, firstTree) .ReplaceSyntaxTree(dummyTree, newLastTree); - // now re-run the drivers and confirm we only ran for the 'new' syntax tree - // but then stopped when we got the same value out + // now re-run the drivers and confirm we only ran the selector for the 'new' syntax tree + // but then cached the result after the transform when we got the same value out syntaxFieldsCalledFor.Clear(); driver = driver.RunGenerators(compilation); results = driver.GetRunResult(); @@ -1409,9 +1489,8 @@ class E step => Assert.Collection(step.Outputs, output => Assert.Equal(("fieldB", IncrementalStepRunReason.Cached), output)), step => Assert.Collection(step.Outputs, - output => Assert.Equal(("fieldC", IncrementalStepRunReason.Unchanged), output))); - Assert.Single(syntaxFieldsCalledFor); - Assert.Equal("fieldC", syntaxFieldsCalledFor[0]); + output => Assert.Equal(("fieldC", IncrementalStepRunReason.Cached), output))); + Assert.Equal("fieldC", Assert.Single(syntaxFieldsCalledFor)); } [Fact] @@ -1449,7 +1528,10 @@ class C }); }); - GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { new IncrementalGeneratorWrapper(testGenerator) }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + GeneratorDriver driver = CSharpGeneratorDriver.Create( + new[] { new IncrementalGeneratorWrapper(testGenerator) }, + parseOptions: parseOptions, + driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); driver = driver.RunGenerators(compilation); var results = driver.GetRunResult(); Assert.Collection(results.Results[0].TrackedSteps["Fields"], @@ -1960,6 +2042,41 @@ class C { } Assert.True(generatorCancelled); } + [Fact] + public void Syntax_Receiver_Cancellation_During_Visit() + { + var source = @" +class C +{ + int Property { get; set; } + + void Function() + { + var x = 5; + x += 4; + } +} +"; + var parseOptions = TestOptions.Regular; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + compilation.VerifyDiagnostics(); + + Assert.Single(compilation.SyntaxTrees); + + var testGenerator = new CallbackGenerator( + onInit: (i) => i.RegisterForSyntaxNotifications(() => new TestSyntaxReceiver(tag: 0, callback: (a) => { if (a is AssignmentExpressionSyntax) { throw new OperationCanceledException("Simulated cancellation from external source"); } })), + onExecute: (e) => { e.AddSource("test", SourceText.From("public class D{}", Encoding.UTF8)); } + ); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions); + driver = driver.RunGenerators(compilation, CancellationToken.None); + var results = driver.GetRunResult(); + + Assert.Single(results.Results); + Assert.IsType(results.Results[0].Exception); + Assert.Equal("Simulated cancellation from external source", results.Results[0].Exception!.Message); + } + private class TestReceiverBase { private readonly Action? _callback; diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs index 6e608104926e4..1dce2da3aa49e 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs @@ -1024,7 +1024,8 @@ public static void Main(string[] args) { }" }); assembly.VerifyEmitDiagnostics(); - CompileAndVerify(assembly); + // ILVerify: Assembly or module not found: a2 + CompileAndVerify(assembly, verify: Verification.FailsILVerify); } [WorkItem(713356, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/713356")] diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs index 52e02c4e90527..975370bae1e53 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelAPITests.cs @@ -4156,6 +4156,147 @@ void M(string S1 = $""Testing"", Namae n = null) Assert.Equal("Level 5", model.GetConstantValue(actual[7]).Value); } + [WorkItem(976, "https://github.com/dotnet/roslyn/issues/976")] + [Fact] + public void ConstantValueOfRawInterpolatedString() + { + var source = @" +class Program +{ + static void Main(string[] args) + { + Console.WriteLine($""""""Hello, world!""""""); + Console.WriteLine($""""""{DateTime.Now.ToString()}.{args[0]}""""""); + } +}"; + + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var actual = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.True(model.GetConstantValue(actual[0]).HasValue); + Assert.Equal("Hello, world!", model.GetConstantValue(actual[0]).Value); + Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[0]).Type.SpecialType); + Assert.False(model.GetConstantValue(actual[1]).HasValue); + } + + [WorkItem(976, "https://github.com/dotnet/roslyn/issues/976")] + [Fact] + public void ConstantValueOfRawInterpolatedString2() + { + var source = @" +class Program +{ + static void Main(string[] args) + { + Console.WriteLine($""""""{0}.{true}""""""); + } +}"; + + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var actual = tree.GetRoot().DescendantNodes().OfType().ToArray(); + + Assert.True(model.GetConstantValue(actual[0]).HasValue); + Assert.Equal(0, model.GetConstantValue(actual[0]).Value); + Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(actual[0]).Type.SpecialType); + + Assert.True(model.GetConstantValue(actual[1]).HasValue); + Assert.Equal(true, model.GetConstantValue(actual[1]).Value); + Assert.Equal(SpecialType.System_Boolean, model.GetTypeInfo(actual[1]).Type.SpecialType); + } + + [WorkItem(976, "https://github.com/dotnet/roslyn/issues/976")] + [Fact] + public void ConstantValueOfRawInterpolatedString3() + { + var source = @" +class Program +{ + static void Main(string[] args) + { + Console.WriteLine($""""""{null}""""""); + } +}"; + + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var actual = tree.GetRoot().DescendantNodes().OfType().ToArray(); + + Assert.True(model.GetConstantValue(actual[0]).HasValue); + Assert.Null(model.GetConstantValue(actual[0]).Value); + Assert.Null(model.GetTypeInfo(actual[0]).Type); + } + + [Fact] + public void ConstantValueOfRawInterpolatedStringComplex() + { + var source = @" +class Program +{ + static void Main(string[] args) + { + const string S1 = $""""""Number 3""""""; + Console.WriteLine($""""""{""""""Level 5""""""} {S1}""""""); + Console.WriteLine($""""""Level {5} {S1}""""""); + } + + void M(string S1 = $""""""Testing"""""", Namae n = null) + { + if (n is Namae { X : $""""""ConstantInterpolatedString""""""}){ + switch(S1){ + case $""""""Level 5"""""": + break; + case $""""""Radio Noise"""""": + goto case $""""""Level 5""""""; + } + } + S1 = S0; + } +}"; + + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var actual = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.Equal(@"$""""""Number 3""""""", actual[0].ToString()); + Assert.Equal("Number 3", model.GetConstantValue(actual[0]).Value); + Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[0]).Type.SpecialType); + + Assert.Equal(@"$""""""{""""""Level 5""""""} {S1}""""""", actual[1].ToString()); + Assert.Equal("Level 5 Number 3", model.GetConstantValue(actual[1]).Value); + Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[1]).Type.SpecialType); + + Assert.False(model.GetConstantValue(actual[2]).HasValue); + Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[2]).Type.SpecialType); + + Assert.Equal(@"$""""""Testing""""""", actual[3].ToString()); + Assert.Equal("Testing", model.GetConstantValue(actual[3]).Value); + Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[3]).Type.SpecialType); + + Assert.Equal(@"$""""""ConstantInterpolatedString""""""", actual[4].ToString()); + Assert.Equal("ConstantInterpolatedString", model.GetConstantValue(actual[4]).Value); + Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[4]).Type.SpecialType); + + Assert.Equal(@"$""""""Level 5""""""", actual[5].ToString()); + Assert.Equal("Level 5", model.GetConstantValue(actual[5]).Value); + Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[5]).Type.SpecialType); + + Assert.Equal(@"$""""""Radio Noise""""""", actual[6].ToString()); + Assert.Equal("Radio Noise", model.GetConstantValue(actual[6]).Value); + Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[6]).Type.SpecialType); + + Assert.Equal(@"$""""""Level 5""""""", actual[7].ToString()); + Assert.Equal("Level 5", model.GetConstantValue(actual[7]).Value); + Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[7]).Type.SpecialType); + } + [WorkItem(814, "https://github.com/dotnet/roslyn/issues/814")] [Fact] public void TypeOfDynamic() diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/UsedAssembliesTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/UsedAssembliesTests.cs index 4e7b87b4dd92b..d1c15f6015ff2 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/UsedAssembliesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/UsedAssembliesTests.cs @@ -32,7 +32,7 @@ interface I1 } "; var comp1 = CreateEmptyCompilation(source); - CompileAndVerify(comp1); + CompileAndVerify(comp1, verify: Verification.FailsILVerify); Assert.Empty(comp1.GetUsedAssemblyReferences()); @@ -53,7 +53,7 @@ public interface I1 } "; var comp1 = CreateEmptyCompilation(source); - CompileAndVerify(comp1); + CompileAndVerify(comp1, verify: Verification.FailsILVerify); var source2 = @" @@ -411,7 +411,7 @@ public interface I1 } "; var comp1 = CreateEmptyCompilation(source); - CompileAndVerify(comp1); + CompileAndVerify(comp1, verify: Verification.FailsILVerify); var source2 = @" diff --git a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs index 39991e02ff2cf..c2b267aa23460 100644 --- a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs @@ -6930,5 +6930,406 @@ class C {{ }}"; "; Assert.Equal(expected, actual); } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_01() + { + var source = @" +/// The record. +/// Parameter of the record. +record Rec(string Value); +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25)); + var expected = +@" + + + Test + + + + The record. + Parameter of the record. + + + The record. + Parameter of the record. + + + Parameter of the record. + + +"; + AssertEx.Equal(expected, actual); + } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_02() + { + var source = @" +/// The record. +/// Parameter of the record. +record Rec(string Value); +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25)); + var expected = +@" + + + Test + + + + + + +"; + AssertEx.Equal(expected, actual); + } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_03() + { + var source = @" +/// The record. +/// Parameter of the record. +/// Also the value of the record. +record Rec(string Value); +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,12): warning CS1571: XML comment has a duplicate param tag for 'Value' + // /// Also the value of the record. + Diagnostic(ErrorCode.WRN_DuplicateParamTag, @"name=""Value""").WithArguments("Value").WithLocation(4, 12), + // (4,12): warning CS1571: XML comment has a duplicate param tag for 'Value' + // /// Also the value of the record. + Diagnostic(ErrorCode.WRN_DuplicateParamTag, @"name=""Value""").WithArguments("Value").WithLocation(4, 12), + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25)); + + var expected = +@" + + + Test + + + + The record. + Parameter of the record. + Also the value of the record. + + + The record. + Parameter of the record. + Also the value of the record. + + + Parameter of the record. + Also the value of the record. + + +"; + AssertEx.Equal(expected, actual); + } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_04() + { + var source = @" +/// The record. +/// First item in the record. +/// Second item in the record. +record Rec(string Item1, object Item2); +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25) +); + var expected = +@" + + + Test + + + + The record. + First item in the record. + Second item in the record. + + + The record. + First item in the record. + Second item in the record. + + + First item in the record. + + + Second item in the record. + + +"; + AssertEx.Equal(expected, actual); + } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_05() + { + var source = @" +/// The record. +/// Second item in the record. +record Rec(string Item1, object Item2); +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,19): warning CS1573: Parameter 'Item1' has no matching param tag in the XML comment for 'Rec.Rec(string, object)' (but other parameters do) + // record Rec(string Item1, object Item2); + Diagnostic(ErrorCode.WRN_MissingParamTag, "Item1").WithArguments("Item1", "Rec.Rec(string, object)").WithLocation(4, 19), + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25)); + var expected = +@" + + + Test + + + + The record. + Second item in the record. + + + The record. + Second item in the record. + + + Second item in the record. + + +"; + AssertEx.Equal(expected, actual); + } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_06() + { + var source = @" +/// The record. +/// Item within the record. +record Rec(string Item) +{ + public string Item { get; init; } = Item; +} +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25)); + var expected = +@" + + + Test + + + + The record. + Item within the record. + + + The record. + Item within the record. + + +"; + AssertEx.Equal(expected, actual); + } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_07() + { + var source = @" +/// The record. +/// Item within the record. +record Rec(string Item) +{ +} +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25)); + var expected = +@" + + + Test + + + + + + +"; + AssertEx.Equal(expected, actual); + } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_08() + { + var source = @" +/** + * The record. + * Item within the record. + * The remarks. + */ +record Rec(string Item) +{ +} +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25)); + var expected = +@" + + + Test + + + + The record. + Item within the record. + The remarks. + + + The record. + Item within the record. + The remarks. + + + Item within the record. + + +"; + AssertEx.Equal(expected, actual); + } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_09() + { + var source = @" +/** + *The record. + *Item within the record. + *The remarks. + */ +record Rec(string Item) +{ +} +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25)); + var expected = +@" + + + Test + + + + The record. + Item within the record. + The remarks. + + + The record. + Item within the record. + The remarks. + + + Item within the record. + + +"; + AssertEx.Equal(expected, actual); + } + + [Fact] + [WorkItem(52663, "https://github.com/dotnet/roslyn/issues/52663")] + public void PositionalRecord_10() + { + var source = @" +/** + The record. + Item within the record. + The remarks. + */ +record Rec(string Item) +{ +} +"; + var comp = CreateCompilationUtil(new[] { source, IsExternalInitTypeDefinition }); + var actual = GetDocumentationCommentText(comp, + // (4,25): warning CS1591: Missing XML comment for publicly visible type or member 'IsExternalInit' + // public static class IsExternalInit + Diagnostic(ErrorCode.WRN_MissingXMLComment, "IsExternalInit").WithArguments("System.Runtime.CompilerServices.IsExternalInit").WithLocation(4, 25)); + + // Ideally, the 'P:Rec.Item' summary would have exactly the same leading indentation as the param comment it was derived from. + // However, it doesn't seem essential for this to match in all cases. + var expected = +@" + + + Test + + + + The record. + Item within the record. + The remarks. + + + The record. + Item within the record. + The remarks. + + + Item within the record. + + +"; + AssertEx.Equal(expected, actual); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 744421583f648..c2911fa059138 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -48,6 +48,14 @@ private static Verification VerifyOnMonoOrCoreClr } } + private static Verification VerifyOnMonoOrCoreClr_FailsIlVerify + { + get + { + return ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.FailsILVerify : Verification.Skipped; + } + } + private void ValidateMethodImplementation_011(string source) { foreach (string access in new[] { "x.M1();", "new System.Action(x.M1)();" }) @@ -9638,7 +9646,7 @@ static void Main() M2 M3", symbolValidator: validate, - verify: VerifyOnMonoOrCoreClr); + verify: VerifyOnMonoOrCoreClr_FailsIlVerify); validate(compilation1.SourceModule); @@ -9702,7 +9710,7 @@ static void Main() CompileAndVerify(compilation4, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : @"M1 M2", - verify: VerifyOnMonoOrCoreClr); + verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var compilation5 = CreateCompilation(source4, options: TestOptions.DebugExe, references: new[] { reference }, @@ -17954,7 +17962,7 @@ static void Main() get_P6 set_P6", symbolValidator: validate, - verify: VerifyOnMonoOrCoreClr); + verify: VerifyOnMonoOrCoreClr_FailsIlVerify); validate(compilation1.SourceModule); @@ -18063,7 +18071,7 @@ static void Main() set_P5 set_P6 ", - verify: VerifyOnMonoOrCoreClr); + verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var compilation5 = CreateCompilation(source4, options: TestOptions.DebugExe, references: new[] { reference }, @@ -28444,7 +28452,7 @@ static void Main() get_P2 set_P2 get_P3 -set_P3", symbolValidator: validate, verify: VerifyOnMonoOrCoreClr); +set_P3", symbolValidator: validate, verify: VerifyOnMonoOrCoreClr_FailsIlVerify); validate(compilation1.SourceModule); @@ -28517,7 +28525,7 @@ static void Main() set_P1 get_P2 set_P2", - verify: VerifyOnMonoOrCoreClr); + verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var compilation5 = CreateCompilation(source4, options: TestOptions.DebugExe, references: new[] { reference }, @@ -29259,7 +29267,7 @@ public void M1() } "; - ValidateNestedTypes_01(source0 + source1, Accessibility.Protected, targetFramework: TargetFramework.NetCoreApp, execute: ExecutionConditionUtil.IsMonoOrCoreClr, verify: VerifyOnMonoOrCoreClr); + ValidateNestedTypes_01(source0 + source1, Accessibility.Protected, targetFramework: TargetFramework.NetCoreApp, execute: ExecutionConditionUtil.IsMonoOrCoreClr, verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular, @@ -29365,7 +29373,7 @@ public void M1() I1+T3 B I1+T5", - verify: VerifyOnMonoOrCoreClr); + verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var compilation5 = CreateCompilation(source2, options: TestOptions.DebugExe, references: new[] { reference }, @@ -29500,7 +29508,7 @@ public void M1() I1+T3 B I1+T5", - verify: VerifyOnMonoOrCoreClr); + verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var compilation5 = CreateCompilation(source2, options: TestOptions.DebugExe, references: new[] { reference }, @@ -29809,7 +29817,7 @@ public void M1() } } "; - ValidateNestedTypes_01(source0 + source1, Accessibility.ProtectedAndInternal, targetFramework: TargetFramework.NetCoreApp, execute: ExecutionConditionUtil.IsMonoOrCoreClr, verify: VerifyOnMonoOrCoreClr); + ValidateNestedTypes_01(source0 + source1, Accessibility.ProtectedAndInternal, targetFramework: TargetFramework.NetCoreApp, execute: ExecutionConditionUtil.IsMonoOrCoreClr, verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular, @@ -32819,7 +32827,7 @@ static void Main() @"I2.M1 I4.M1 ", - verify: VerifyOnMonoOrCoreClr, + verify: VerifyOnMonoOrCoreClr_FailsIlVerify, symbolValidator: ValidateMethodImplementationInDerived_01); foreach (var reference in new[] { compilation1.ToMetadataReference(), compilation1.EmitToImageReference() }) @@ -33065,7 +33073,7 @@ static void Main() @"I2.M1 I4.M1 ", - verify: VerifyOnMonoOrCoreClr, + verify: VerifyOnMonoOrCoreClr_FailsIlVerify, symbolValidator: ValidateMethodImplementationInDerived_01); foreach (var reference in new[] { compilation1.ToMetadataReference(), compilation1.EmitToImageReference() }) @@ -38928,7 +38936,7 @@ public static void Test() @"123 -2 ", - verify: VerifyOnMonoOrCoreClr, symbolValidator: validate); + verify: VerifyOnMonoOrCoreClr_FailsIlVerify, symbolValidator: validate); var source2 = @" @@ -38950,7 +38958,7 @@ static void Main() parseOptions: TestOptions.Regular, targetFramework: TargetFramework.NetCoreApp); - CompileAndVerify(compilation2, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "1122" : null, verify: VerifyOnMonoOrCoreClr); + CompileAndVerify(compilation2, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "1122" : null, verify: VerifyOnMonoOrCoreClr_FailsIlVerify); } var source3 = @@ -44779,7 +44787,7 @@ static void Main() var compilation0 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, targetFramework: TargetFramework.NetCoreApp); compilation0.VerifyDiagnostics(); - CompileAndVerify(compilation0, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : @"M1", verify: VerifyOnMonoOrCoreClr); + CompileAndVerify(compilation0, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : @"M1", verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var source2 = @" interface I2 : I3 @@ -44805,7 +44813,7 @@ static void Main() var compilation1 = CreateCompilation(source0 + source2, options: TestOptions.DebugExe, targetFramework: TargetFramework.NetCoreApp); compilation1.VerifyDiagnostics(); - CompileAndVerify(compilation1, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : @"M1", verify: VerifyOnMonoOrCoreClr); + CompileAndVerify(compilation1, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : @"M1", verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var source3 = @" interface I2 : I3 @@ -44942,8 +44950,7 @@ static void Main() var compilation0 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, targetFramework: TargetFramework.NetCoreApp); compilation0.VerifyDiagnostics(); - CompileAndVerify(compilation0, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : @"M1", verify: VerifyOnMonoOrCoreClr); - + CompileAndVerify(compilation0, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : @"M1", verify: VerifyOnMonoOrCoreClr_FailsIlVerify); var source3 = @" class I2 @@ -45003,7 +45010,7 @@ static void Main() var compilation0 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, targetFramework: TargetFramework.NetCoreApp); compilation0.VerifyDiagnostics(); - CompileAndVerify(compilation0, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : @"M1", verify: VerifyOnMonoOrCoreClr); + CompileAndVerify(compilation0, expectedOutput: !ExecutionConditionUtil.IsMonoOrCoreClr ? null : @"M1", verify: VerifyOnMonoOrCoreClr_FailsIlVerify); } private const string NoPiaAttributes = @" @@ -45463,6 +45470,7 @@ void ITest33.M1(){} var piaCompilation = CreateCompilation(pia, options: TestOptions.ReleaseDll, references: new[] { attributesRef }, targetFramework: TargetFramework.NetCoreApp); + // ILVerify: Missing method 'Void UsePia.Test(ITest33)' CompileAndVerify(piaCompilation, verify: VerifyOnMonoOrCoreClr); string consumer1 = @" @@ -45516,7 +45524,8 @@ public interface ITest33 foreach (var reference2 in new[] { compilation1.ToMetadataReference(), compilation1.EmitToImageReference() }) { var compilation2 = CreateCompilation(consumer2, options: TestOptions.ReleaseExe, references: new[] { reference2, pia2Reference }, targetFramework: TargetFramework.StandardLatest); - CompileAndVerify(compilation2, expectedOutput: "Test.M1"); + // ILVerify: Missing method 'Void UsePia.Test(ITest33)' + CompileAndVerify(compilation2, expectedOutput: "Test.M1", verify: Verification.Skipped); } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs index b55e4e942dc56..15c12f5979dd0 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs @@ -290,11 +290,12 @@ static void Goo(this string x) Console.WriteLine(x); } }"; + // ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 21 } CompileAndVerify(source, expectedOutput: @"ABC 123 123 -xyz"); +xyz", verify: Verification.FailsILVerify); } [WorkItem(541143, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541143")] @@ -376,7 +377,8 @@ static void Main() static void Goo(this T x) { } } "; - CompileAndVerify(source, expectedOutput: "2"); + // ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 7 } + CompileAndVerify(source, expectedOutput: "2", verify: Verification.FailsILVerify); } [WorkItem(528426, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528426")] @@ -873,7 +875,8 @@ internal static void F(this object o) { } internal static void F(this object x, object y) { } internal static void G(this object x, object y) { } }"; - var compilation = CompileAndVerify(source); + // ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 8 } + var compilation = CompileAndVerify(source, verify: Verification.FailsILVerify); compilation.VerifyIL("N.C.M", @"{ // Code size 71 (0x47) @@ -939,7 +942,8 @@ internal static void F2(this object x, object y) { } internal static void F3(this object x, int y) { } internal static void F4(this object x, object y) { } }"; - var compilation = CompileAndVerify(source); + // ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 8 } + var compilation = CompileAndVerify(source, verify: Verification.FailsILVerify); compilation.VerifyIL("N.C.M", @" { @@ -1923,7 +1927,8 @@ public static void M(this C c, int i) System.Console.Write(c.P * i); } }"; - CompileAndVerify(source, expectedOutput: "6"); + // ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 11 } + CompileAndVerify(source, expectedOutput: "6", verify: Verification.FailsILVerify); } [Fact] @@ -2255,7 +2260,7 @@ .maxstack 3 IL_0024: call ""string System.Linq.Enumerable.Aggregate(System.Collections.Generic.IEnumerable, System.Func)"" IL_0029: ret }"; - var compilation = CompileAndVerify(source, expectedOutput: "orange, apple"); + var compilation = CompileAndVerify(source, parseOptions: TestOptions.Regular10, expectedOutput: "orange, apple"); compilation.VerifyIL("C.F", code); compilation.VerifyIL("C.G", code); } @@ -2293,11 +2298,12 @@ static void M(Action a) a(); } }"; + // ILVerify: Unrecognized arguments for delegate .ctor. var compilation = CompileAndVerify(source, expectedOutput: @"F: System.Int32 F: S G: System.Int32 -G: S"); +G: S", verify: Verification.FailsILVerify); compilation.VerifyIL("C.Main", @"{ // Code size 105 (0x69) @@ -2373,12 +2379,13 @@ internal static void M(this object o) Console.WriteLine(""{0}"", o.GetType()); } }"; + // ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 12 } var compilation = CompileAndVerify(source, expectedOutput: @"System.Object System.Object System.Int32 B -B"); +B", verify: Verification.FailsILVerify); compilation.VerifyIL("C.M", @"{ // Code size 112 (0x70) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs index ff03dca45b69e..eff7c789939f4 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs @@ -563,6 +563,27 @@ struct S private static string s1 = $""""; private static readonly string s2 = $""""; } +"); + + comp.VerifyDiagnostics(); + } + + [Fact] + public void UnreferencedRawInterpolatedStringConstants() + { + var comp = CreateCompilation(@" +class C +{ + private static string s1 = $"""""" """"""; + private static readonly string s2 = $"""""" """"""; + private string s3 = $"""""" """"""; + private readonly string s4 = $"""""" """"""; +} +struct S +{ + private static string s1 = $"""""" """"""; + private static readonly string s2 = $"""""" """"""; +} "); comp.VerifyDiagnostics(); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/NullablePublicAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/NullablePublicAPITests.cs index 2afbe863c3509..fe4dd2aabd837 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/NullablePublicAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/NullablePublicAPITests.cs @@ -2527,7 +2527,7 @@ class C void M(object o1, object? o2) { foreach ((var o3, object? o4) in GetList(o1)) {} - foreach ((var o3, object o4) in GetList(o2)) { o3.ToString(); } + foreach ((var o3, object o4) in GetList(o2)) { o3.ToString(); } // 1 o1 = null; foreach ((var o3, object o4) in GetList(o1)) {} _ = o2 ?? throw null!; @@ -2536,7 +2536,10 @@ void M(object o1, object? o2) }"; var comp = CreateCompilation(source, options: WithNullableEnable()); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (10,56): warning CS8602: Dereference of a possibly null reference. + // foreach ((var o3, object o4) in GetList(o2)) { o3.ToString(); } // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o3").WithLocation(10, 56)); var syntaxTree = comp.SyntaxTrees[0]; var root = syntaxTree.GetRoot(); @@ -2544,8 +2547,6 @@ void M(object o1, object? o2) var declarations = root.DescendantNodes().OfType().ToList(); - // Some annotations are incorrect because of https://github.com/dotnet/roslyn/issues/37491 - assertAnnotation(declarations[0], PublicNullableAnnotation.Annotated); assertAnnotation(declarations[1], PublicNullableAnnotation.Annotated); assertAnnotation(declarations[2], PublicNullableAnnotation.Annotated); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs index b3fb8b3223b8f..6a67850bdf48b 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs @@ -21,7 +21,7 @@ private CompilationVerifier CompileAndVerify(CSharpTestSource src, string? expec expectedOutput: expectedOutput, parseOptions: TestOptions.Regular9, // init-only fails verification - verify: Verification.Skipped); + verify: Verification.FailsPEVerify); [Fact] public void GeneratedConstructor() @@ -749,7 +749,8 @@ public void RecordClone1() Assert.Equal(1, ctor.ParameterCount); Assert.True(ctor.Parameters[0].Type.Equals(c, TypeCompareKind.ConsiderEverything)); - var verifier = CompileAndVerify(comp, verify: Verification.Fails).VerifyDiagnostics(); + // PEVerify: Cannot change initonly field outside its .ctor. + var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("C." + WellKnownMemberNames.CloneMethodName, @" { // Code size 7 (0x7) @@ -801,7 +802,8 @@ public C(C other) Assert.Equal(1, ctor.ParameterCount); Assert.True(ctor.Parameters[0].Type.Equals(c, TypeCompareKind.ConsiderEverything)); - var verifier = CompileAndVerify(comp, verify: Verification.Fails).VerifyDiagnostics(); + // PEVerify: Cannot change initonly field outside its .ctor. + var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("C." + WellKnownMemberNames.CloneMethodName, @" { // Code size 7 (0x7) @@ -897,7 +899,8 @@ public record C(int x, int y) Assert.Equal(1, ctor.ParameterCount); Assert.True(ctor.Parameters[0].Type.Equals(c, TypeCompareKind.ConsiderEverything)); - var verifier = CompileAndVerify(comp, verify: Verification.Fails).VerifyDiagnostics( + // PEVerify: Cannot change initonly field outside its .ctor. + var verifier = CompileAndVerify(comp, verify: Verification.FailsPEVerify).VerifyDiagnostics( // (5,25): warning CS0067: The event 'C.E' is never used // public event Action E; Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E").WithLocation(5, 25) @@ -965,7 +968,7 @@ public static void Main() Console.WriteLine(c.Equals(c2)); Console.WriteLine(c.Equals((object)c2)); } -}", expectedOutput: @"False +}", verify: Verification.Passes, expectedOutput: @"False False True True").VerifyDiagnostics( @@ -1049,7 +1052,7 @@ record C public int X { get; } public string Y { get; } public event Action E; -}").VerifyDiagnostics( +}", verify: Verification.Passes).VerifyDiagnostics( // (7,25): warning CS0067: The event 'C.E' is never used // public event Action E; Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E").WithLocation(7, 25) @@ -1804,22 +1807,5 @@ static void Main() CompileAndVerify(src1 + src2 + src3, expectedOutput: "C { Y = 22, X = 11, U = 44, Z = 33 }").VerifyDiagnostics(); CompileAndVerify(new[] { src1, src2, src3 }, expectedOutput: "C { Y = 22, X = 11, U = 44, Z = 33 }").VerifyDiagnostics(); } - - [Fact] - public void EqualityContractGetter_CompilerGeneratedAttribute() - { - var verifier = CompileAndVerify(@" -using System; - -record C; -", symbolValidator: validate); - - static void validate(ModuleSymbol module) - { - var member = module.GlobalNamespace.GetTypeMember("C").GetMember("get_EqualityContract"); - var attributes = member.GetAttributes(); - Assert.Equal(new[] { "CompilerGeneratedAttribute" }, GetAttributeNames(attributes)); - } - } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index 8384e21906a84..1c2c2532ba11d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -12152,18 +12152,24 @@ static System.Action M02() where T : U where U : I1 verifier.VerifyIL("Test.M02()", @" { - // Code size 24 (0x18) + // Code size 39 (0x27) .maxstack 2 .locals init (System.Action V_0) IL_0000: nop - IL_0001: ldnull - IL_0002: constrained. ""T"" - IL_0008: ldftn ""void I1.M01()"" - IL_000e: newobj ""System.Action..ctor(object, System.IntPtr)"" - IL_0013: stloc.0 - IL_0014: br.s IL_0016 - IL_0016: ldloc.0 - IL_0017: ret + IL_0001: ldsfld ""System.Action Test.<>O.<0>__M01"" + IL_0006: dup + IL_0007: brtrue.s IL_0022 + IL_0009: pop + IL_000a: ldnull + IL_000b: constrained. ""T"" + IL_0011: ldftn ""void I1.M01()"" + IL_0017: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_001c: dup + IL_001d: stsfld ""System.Action Test.<>O.<0>__M01"" + IL_0022: stloc.0 + IL_0023: br.s IL_0025 + IL_0025: ldloc.0 + IL_0026: ret } "); @@ -12176,13 +12182,19 @@ .locals init (System.Action V_0) verifier.VerifyIL("Test.M02()", @" { - // Code size 19 (0x13) + // Code size 34 (0x22) .maxstack 2 - IL_0000: ldnull - IL_0001: constrained. ""T"" - IL_0007: ldftn ""void I1.M01()"" - IL_000d: newobj ""System.Action..ctor(object, System.IntPtr)"" - IL_0012: ret + IL_0000: ldsfld ""System.Action Test.<>O.<0>__M01"" + IL_0005: dup + IL_0006: brtrue.s IL_0021 + IL_0008: pop + IL_0009: ldnull + IL_000a: constrained. ""T"" + IL_0010: ldftn ""void I1.M01()"" + IL_0016: newobj ""System.Action..ctor(object, System.IntPtr)"" + IL_001b: dup + IL_001c: stsfld ""System.Action Test.<>O.<0>__M01"" + IL_0021: ret } "); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 8460615ecac40..28e5a750d7088 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -6072,7 +6072,8 @@ class A {} s_mod2.GetReference(), }); - CompileAndVerify(comp).VerifyDiagnostics(); + // ILVerify: Assembly or module not found: ErrTestMod02 + CompileAndVerify(comp, verify: Verification.FailsILVerify).VerifyDiagnostics(); } [Fact()] diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/LineSpanDirectiveTests.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/LineSpanDirectiveTests.cs index 511f88fc20c2e..467fed76f7360 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/LineSpanDirectiveTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/LineSpanDirectiveTests.cs @@ -508,7 +508,7 @@ static int getTextPosition(TextLineCollection lines, LinePosition position) } [Fact] - public void Diagnostics() + public void Diagnostics_01() { var source = @"class Program @@ -536,6 +536,53 @@ static void Main() Diagnostic(ErrorCode.ERR_NameNotInContext, "B").WithArguments("B").WithLocation(8, 9)); } + [Fact] + public void Diagnostics_02() + { + var source = +@"class Program +{ + static void Main() + { +#line (100, 1) - (100, ) 1 ""a.txt"" + A(); +#line (200, 1) - (200, 100) 2 ""b.txt"" + B(); +#line (300, 1) - (300, 100) x ""c.txt"" + C(); + } +}".NormalizeLineEndings(); + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,24): error CS8938: The #line directive value is missing or out of range + // #line (100, 1) - (100, ) 1 "a.txt" + Diagnostic(ErrorCode.ERR_LineSpanDirectiveInvalidValue, ")").WithLocation(5, 24), + // (6,9): error CS0103: The name 'A' does not exist in the current context + // A(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "A").WithArguments("A").WithLocation(6, 9), + // (10,9): error CS0103: The name 'C' does not exist in the current context + // C(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(10, 9), + // b.txt(200,8): error CS0103: The name 'B' does not exist in the current context + // B(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "B").WithArguments("B").WithLocation(200, 8), + // b.txt(201,29): error CS1578: Quoted file name, single-line comment or end-of-line expected + // #line (300, 1) - (300, 100) x "c.txt" + Diagnostic(ErrorCode.ERR_MissingPPFile, "x").WithLocation(201, 29)); + + var tree = comp.SyntaxTrees[0]; + var actualLineMappings = GetLineMappings(tree); + var expectedLineMappings = new[] + { + "(0,0)-(3,7) -> : (0,0)-(3,7)", + "(5,0)-(5,14) -> : (5,0)-(5,14)", + "(7,0)-(7,14),1 -> b.txt: (199,0)-(199,100)", + "(9,0)-(11,1) -> : (9,0)-(11,1)" + }; + AssertEx.Equal(expectedLineMappings, actualLineMappings); + } + [Fact] public void SequencePoints() { diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs index 1a33dd7845880..8b639a7788bcf 100644 --- a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalTests.cs @@ -1206,7 +1206,37 @@ public void TestVerbatimIdentifierWithNoCharacters() [Fact] [Trait("Feature", "Literals")] - public void TestVerbatimIdentifierWithNoCharactersAndTrivia() + public void TestVerbatimIdentifierWithNoCharacters2() + { + var text = "@@"; + var token = LexToken(text); + + Assert.NotEqual(default, token); + Assert.Equal(SyntaxKind.BadToken, token.Kind()); + var errors = token.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_ExpectedVerbatimLiteral, errors[0].Code); + Assert.Equal(text, token.Text); + } + + [Fact] + [Trait("Feature", "Literals")] + public void TestVerbatimIdentifierWithNoCharacters3() + { + var text = "@@@"; + var token = LexToken(text); + + Assert.NotEqual(default, token); + Assert.Equal(SyntaxKind.BadToken, token.Kind()); + var errors = token.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_ExpectedVerbatimLiteral, errors[0].Code); + Assert.Equal(text, token.Text); + } + + [Fact] + [Trait("Feature", "Literals")] + public void TestVerbatimIdentifierWithNoCharactersAndTrivia1() { var text = "@ "; var token = LexToken(text); @@ -1220,6 +1250,70 @@ public void TestVerbatimIdentifierWithNoCharactersAndTrivia() var trivia = token.GetTrailingTrivia().ToList(); } + [Fact] + [Trait("Feature", "Literals")] + public void TestVerbatimIdentifierWithNoCharactersAndTrivia2() + { + var text = "@@ "; + var token = LexToken(text); + + Assert.NotEqual(default, token); + Assert.Equal(SyntaxKind.BadToken, token.Kind()); + var errors = token.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_ExpectedVerbatimLiteral, errors[0].Code); + Assert.Equal(text, token.ToFullString()); + var trivia = token.GetTrailingTrivia().ToList(); + } + + [Fact] + [Trait("Feature", "Literals")] + public void TestVerbatimIdentifierWithNoCharactersAndTrivia3() + { + var text = "@@@ "; + var token = LexToken(text); + + Assert.NotEqual(default, token); + Assert.Equal(SyntaxKind.BadToken, token.Kind()); + var errors = token.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal((int)ErrorCode.ERR_ExpectedVerbatimLiteral, errors[0].Code); + Assert.Equal(text, token.ToFullString()); + var trivia = token.GetTrailingTrivia().ToList(); + } + + [Fact] + [Trait("Feature", "Literals")] + public void TestVerbatimIdentifierWithMultipleAtSign1() + { + var text = "@@class"; + var token = LexToken(text); + + Assert.NotEqual(default, token); + Assert.Equal(SyntaxKind.IdentifierToken, token.Kind()); + var errors = token.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal(ErrorCode.ERR_IllegalAtSequence, (ErrorCode)errors[0].Code); + Assert.Equal(text, token.Text); + Assert.Equal("class", token.ValueText); + } + + [Fact] + [Trait("Feature", "Literals")] + public void TestVerbatimIdentifierWithMultipleAtSign2() + { + var text = "@@@class"; + var token = LexToken(text); + + Assert.NotEqual(default, token); + Assert.Equal(SyntaxKind.IdentifierToken, token.Kind()); + var errors = token.Errors(); + Assert.Equal(1, errors.Length); + Assert.Equal(ErrorCode.ERR_IllegalAtSequence, (ErrorCode)errors[0].Code); + Assert.Equal(text, token.Text); + Assert.Equal("class", token.ValueText); + } + [Fact] [Trait("Feature", "Literals")] public void TestNumericLiteral() diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/RawStringLiteralLexingTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/RawStringLiteralLexingTests.cs new file mode 100644 index 0000000000000..6c16aeb89fe36 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/RawStringLiteralLexingTests.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.LexicalAndXml +{ + public class RawStringLiteralLexingTests : CompilingTestBase + { + [Theory] + #region Single Line Cases + [InlineData("\"\"\"{|CS8997:|}", SyntaxKind.SingleLineRawStringLiteralToken, "")] + [InlineData("\"\"\" {|CS8997:|}", SyntaxKind.SingleLineRawStringLiteralToken, " ")] + [InlineData("\"\"\" \"{|CS8997:|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"")] + [InlineData("\"\"\" \"\"{|CS8997:|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"\"")] + [InlineData("\"\"\" \"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, " ")] + [InlineData("\"\"\"\t\"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, "\t")] + [InlineData("\"\"\"a\"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, "a")] + [InlineData("\"\"\"abc\"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, "abc")] + [InlineData("\"\"\" abc \"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, " abc ")] + [InlineData("\"\"\" abc \"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, " abc ")] + [InlineData("\"\"\" \" \"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, " \" ")] + [InlineData("\"\"\" \"\" \"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, " \"\" ")] + [InlineData("\"\"\"\" \"\"\" \"\"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, " \"\"\" ")] + [InlineData("\"\"\"'\"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, "'")] + [InlineData("\"\"\" \"\"\"{|CS8998:\"|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"\"\"\"")] + [InlineData("\"\"\" \"\"\"{|CS8998:\"\"|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"\"\"\"\"")] + [InlineData("\"\"\" \"\"\"{|CS8998:\"\"\"|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"\"\"\"\"\"")] + [InlineData("\"\"\" \"\"\"{|CS8998:\"\"\"\"|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"\"\"\"\"\"\"")] + [InlineData("\"\"\"a{|CS8997:\n|}", SyntaxKind.SingleLineRawStringLiteralToken, "a")] + [InlineData("\"\"\" a {|CS8997:\n|}", SyntaxKind.SingleLineRawStringLiteralToken, " a ")] + [InlineData("\"\"\" \"{|CS8997:\n|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"")] + [InlineData("\"\"\" \"\"{|CS8997:\n|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"\"")] + [InlineData("\"\"\"a{|CS8997:\r\n|}", SyntaxKind.SingleLineRawStringLiteralToken, "a")] + [InlineData("\"\"\" a {|CS8997:\r\n|}", SyntaxKind.SingleLineRawStringLiteralToken, " a ")] + [InlineData("\"\"\" \"{|CS8997:\r\n|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"")] + [InlineData("\"\"\" \"\"{|CS8997:\r\n|}", SyntaxKind.SingleLineRawStringLiteralToken, " \"\"")] + #endregion + #region Multi Line Cases + [InlineData("\"\"\"\n{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\n")] + [InlineData("\"\"\"\n\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\n\"")] + [InlineData("\"\"\"\n\"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\n\"\"")] + [InlineData("\"\"\"\n{|CS9002:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, "\n\"\"\"")] + [InlineData("\"\"\"\n\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\" \n\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \n\"")] + [InlineData("\"\"\" \n\"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \n\"\"")] + [InlineData("\"\"\" \n{|CS9002:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \n\"\"\"")] + [InlineData("\"\"\" \n\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\" \n\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \n\"")] + [InlineData("\"\"\" \n\"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \n\"\"")] + [InlineData("\"\"\" \n{|CS9002:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \n\"\"\"")] + [InlineData("\"\"\" \n\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\"\n \"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\n \"")] + [InlineData("\"\"\"\n \"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\n \"\"")] + [InlineData("\"\"\" \n \"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \n \"\"")] + [InlineData("\"\"\" \n \"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \n \"\"")] + [InlineData("\"\"\" \n {|CS9002:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \n \"\"\"")] + [InlineData("\"\"\" \n\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\" \na\"\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "a\"")] + [InlineData("\"\"\" \na\"\"\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "a\"\"")] + [InlineData("\"\"\" \n\"a\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\"a")] + [InlineData("\"\"\" \n\"\"a\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\"\"a")] + [InlineData("\"\"\" \na{|CS9000:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \na\"\"\"")] + [InlineData("\"\"\" \na{|CS9000:\"\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \na\"\"\"\"")] + [InlineData("\"\"\" \na\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "a")] + [InlineData("\"\"\" \n a\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " a")] + [InlineData("\"\"\" \na \n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "a ")] + [InlineData("\"\"\" \n a \n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " a ")] + [InlineData("\"\"\" \na\n\"\"\"{|CS8998:\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \na\n\"\"\"\"")] + [InlineData("\"\"\" \na\n\"\"\"{|CS8998:\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \na\n\"\"\"\"\"")] + [InlineData("\"\"\" \na\n\"\"\"{|CS8998:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \na\n\"\"\"\"\"\"")] + [InlineData("\"\"\"\r\n{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n")] + [InlineData("\"\"\"\r\n\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n\"")] + [InlineData("\"\"\"\r\n\"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n\"\"")] + [InlineData("\"\"\"\r\n{|CS9002:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n\"\"\"")] + [InlineData("\"\"\"\r\n\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\" \r\n\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\n\"")] + [InlineData("\"\"\" \r\n\"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\n\"\"")] + [InlineData("\"\"\" \r\n{|CS9002:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\n\"\"\"")] + [InlineData("\"\"\" \r\n\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\" \r\n\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\n\"")] + [InlineData("\"\"\" \r\n\"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\n\"\"")] + [InlineData("\"\"\" \r\n{|CS9002:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\n\"\"\"")] + [InlineData("\"\"\" \r\n\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\"\r\n \"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n \"")] + [InlineData("\"\"\"\r\n \"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n \"\"")] + [InlineData("\"\"\" \r\n \"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\n \"\"")] + [InlineData("\"\"\" \r\n \"\"{|CS8997:|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\n \"\"")] + [InlineData("\"\"\" \r\n {|CS9002:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\n \"\"\"")] + [InlineData("\"\"\" \r\n\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\" \r\na{|CS9000:\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\na\"\"\"")] + [InlineData("\"\"\" \r\na{|CS9000:\"\"\"\"|}", SyntaxKind.MultiLineRawStringLiteralToken, " \r\na\"\"\"\"")] + [InlineData("\"\"\" \r\na\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "a")] + [InlineData("\"\"\" \r\n a\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " a")] + [InlineData("\"\"\" \r\na \r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "a ")] + [InlineData("\"\"\" \r\n a \r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " a ")] + [InlineData("\"\"\" \r\n\r\n a \r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n a ")] + [InlineData("\"\"\" \r\n a \r\n\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " a \r\n")] + [InlineData("\"\"\" \r\n\r\n a \r\n\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n a \r\n")] + [InlineData("\"\"\" \n\"\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\"")] + [InlineData("\"\"\" \n\"\"\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\"\"")] + [InlineData("\"\"\"\" \n\"\"\"\n\"\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\"\"\"")] + #endregion + #region Multi Line Indentation Cases + [InlineData("\"\"\"\r\n abc\r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc\r\n def")] + [InlineData("\"\"\"\"\r\n \"\"\"\r\n \"\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\"\"\"")] + [InlineData("\"\"\"\r\n \r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\"\r\n \"\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\"")] + [InlineData("\"\"\"\r\n\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\"\r\n abc\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc")] + [InlineData("\"\"\"\n\n\t\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\"\r\n{|CS8999: |}abc\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n abc\r\n \"\"\"")] + [InlineData("\"\"\"\r\n abc\r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " abc\r\n def")] + [InlineData("\"\"\"\r\n \" abc \"\r\n \"\" def \"\"\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " \" abc \"\r\n \"\" def \"\"")] + [InlineData("\"\"\"\r\n \r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " ")] + [InlineData("\"\"\"\r\n \" abc \"\r\n \"\" def \"\"\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " \" abc \"\r\n \"\" def \"\"")] + [InlineData("\"\"\"\n{|CS9003:\t|}\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\n\t\n \"\"\"")] + [InlineData("\"\"\"\r\n abc \r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc ")] + [InlineData("\"\"\"\r\n abc \r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " abc ")] + [InlineData("\"\"\"\r\n \" abc \"\r\n \"\" def \"\"\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\" abc \"\r\n\"\" def \"\"")] + [InlineData("\"\"\"\r\n abc \r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc ")] + [InlineData("\"\"\"\r\n abc\r\n{|CS8999:|}def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n abc\r\ndef\r\n \"\"\"")] + [InlineData("\"\"\"\r\n \r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\"\n{|CS9003: |}\n\t\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\n \n\t\"\"\"")] + [InlineData("\"\"\"\r\n abc\r\n\r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc\r\n\r\ndef")] + [InlineData("\"\"\"\r\n abc\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc")] + [InlineData("\"\"\"\r\n abc\r\n \r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc\r\n \r\ndef")] + [InlineData("\"\"\"\r\n abc \r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " abc ")] + [InlineData("\"\"\"\r\n abc\r\n \r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc\r\n \r\ndef")] + [InlineData("\"\"\"\n\t\n\t\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "")] + [InlineData("\"\"\"\r\n{|CS8999:|}abc\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\r\nabc\r\n \"\"\"")] + [InlineData("\"\"\"\r\n abc \r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " abc ")] + [InlineData("\"\"\"\r\n abc\r\n \r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc\r\n \r\ndef")] + [InlineData("\"\"\"\r\n \r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " ")] + [InlineData("\"\"\"\n{|CS9003: |}abc\n\t\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\n abc\n\t\"\"\"")] + [InlineData("\"\"\"\r\n abc\r\n \r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc\r\n\r\ndef")] + [InlineData("\"\"\"\r\n abc\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " abc")] + [InlineData("\"\"\"\n{|CS9003:\t|}abc\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\n\tabc\n \"\"\"")] + [InlineData("\"\"\"\n{|CS8999: |}abc\n \t\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\n abc\n \t\"\"\"")] + [InlineData("\"\"\"\n\t\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\t")] + [InlineData("\"\"\"\r\n abc\r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " abc\r\ndef")] + [InlineData("\"\"\"\n \tabc\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\tabc")] + [InlineData("\"\"\"\r\n abc\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " abc")] + [InlineData("\"\"\"\r\n abc\r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "abc\r\ndef")] + [InlineData("\"\"\"\r\n \"\"\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\"\"")] + [InlineData("\"\"\"\r\n \"abc\"\r\n \"\"def\"\"\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, " \"abc\"\r\n \"\"def\"\"")] + [InlineData("\"\"\"\r\n{|CS8999: |}abc\r\n\r\n def\r\n \"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, "\r\n abc\r\n\r\n def\r\n \"\"\"")] + #endregion + public void TestSingleToken(string markup, SyntaxKind expectedKind, string expectedValue) + => TestSingleTokenWorker(markup, expectedKind, expectedValue, testOutput: true); + + private void TestSingleTokenWorker(string markup, SyntaxKind expectedKind, string expectedValue, bool testOutput) + { + TestSingleTokenWorker(markup, expectedKind, expectedValue, leadingTrivia: false, trailingTrivia: false, testOutput); + TestSingleTokenWorker(markup, expectedKind, expectedValue, leadingTrivia: true, trailingTrivia: false, testOutput); + + // If we don't have an unterminated raw string, then also try with some trailing trivia attached. + if (!markup.Contains("CS" + (int)ErrorCode.ERR_UnterminatedRawString)) + { + TestSingleTokenWorker(markup, expectedKind, expectedValue, leadingTrivia: false, trailingTrivia: true, testOutput); + TestSingleTokenWorker(markup, expectedKind, expectedValue, leadingTrivia: true, trailingTrivia: true, testOutput); + } + } + + private void TestSingleTokenWorker( + string markup, SyntaxKind expectedKind, string expectedValue, bool leadingTrivia, bool trailingTrivia, bool testOutput) + { + if (leadingTrivia) + markup = " /*leading*/ " + markup; + + if (trailingTrivia) + markup += " // trailing"; + + MarkupTestFile.GetSpans(markup, out var input, out IDictionary> spans); + + Assert.True(spans.Count == 0 || spans.Count == 1); + + var token = SyntaxFactory.ParseToken(input); + var literal = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, token); + token = literal.Token; + + Assert.Equal(expectedKind, token.Kind()); + Assert.Equal(input.Length, token.FullWidth); + Assert.Equal(input, token.ToFullString()); + Assert.NotNull(token.Value); + Assert.IsType(token.Value); + Assert.NotNull(token.ValueText); + Assert.Equal(expectedValue, token.ValueText); + + if (spans.Count == 0) + { + Assert.Empty(token.GetDiagnostics()); + + if (testOutput) + { + + var programText = @$" +System.Console.WriteLine( +{input} +); +"; + + this.CompileAndVerify(programText, expectedOutput: expectedValue); + } + } + else + { + Assert.Equal(1, spans.Count); + + var diagnostics = token.GetDiagnostics(); + + Assert.All(diagnostics, d => Assert.Equal(spans.Single().Key, d.Id)); + + var expectedDiagnosticSpans = spans.Single().Value.OrderBy(d => d.Start); + var actualDiagnosticsSpans = diagnostics.Select(d => d.Location.SourceSpan).OrderBy(d => d.Start); + + Assert.Equal(expectedDiagnosticSpans, actualDiagnosticsSpans); + } + } + + [Fact] + public void TestDirectiveWithRawString() + { + CreateCompilation( +@" +#line 1 """"""c:\""""""").VerifyDiagnostics( + // (2,9): error CS8996: Raw string literals are not allowed in preprocessor directives + // #line 1 """c:\""" + Diagnostic(ErrorCode.ERR_RawStringNotInDirectives, "").WithLocation(2, 9)); + } + + [Fact] + public void AllSingleCharactersInSingleLineLiteral() + { + for (var charValue = '\0'; ; charValue++) + { + if (charValue == '"' || SyntaxFacts.IsNewLine(charValue)) + continue; + + TestSingleTokenWorker( + "\"\"\"" + charValue + "\"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, charValue.ToString(), testOutput: false); + + if (charValue == char.MaxValue) + break; + } + } + + [Fact] + public void AllSingleCharactersInMultiLineLiteral() + { + for (var charValue = '\0'; ; charValue++) + { + TestSingleTokenWorker( + "\"\"\"\r\n" + charValue + "\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, charValue.ToString(), testOutput: false); + + if (charValue == char.MaxValue) + break; + } + } + + public static IEnumerable EscapeSequences => new[] + { + new object[] { "\\'" }, + new object[] { "\\\"" }, + new object[] { "\\\\" }, + new object[] { "\\0" }, + new object[] { "\\a" }, + new object[] { "\\b" }, + new object[] { "\\f" }, + new object[] { "\\n" }, + new object[] { "\\r" }, + new object[] { "\\t" }, + new object[] { "\\v" }, + new object[] { "\\u1234" }, + new object[] { "\\U12345678" }, + new object[] { "\\x1234" }, + }; + + [Theory, MemberData(nameof(EscapeSequences))] + public void AllEscapeSequencesInSingleLineLiteral(string escapeSequence) + { + TestSingleToken("\"\"\" " + escapeSequence + " \"\"\"", SyntaxKind.SingleLineRawStringLiteralToken, $" {escapeSequence} "); + } + + [Theory, MemberData(nameof(EscapeSequences))] + public void AllEscapeSequencesInMultiLineLiteral(string escapeSequence) + { + TestSingleToken("\"\"\"\r\n" + escapeSequence + "\r\n\"\"\"", SyntaxKind.MultiLineRawStringLiteralToken, escapeSequence); + } + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs index 8fa08646a5360..f6c25667d5b3e 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs @@ -7432,7 +7432,7 @@ public void TestOptParamMethodDeclarationWithNullValidationNoSpaces() } [Fact] - public void TestNullCheckedArgList() + public void TestNullCheckedArgList1() { UsingStatement(@"void M(__arglist!) { }", options: TestOptions.RegularPreview, // (1,17): error CS1003: Syntax error, ',' expected @@ -7463,6 +7463,173 @@ public void TestNullCheckedArgList() EOF(); } + [Fact] + public void TestNullCheckedArgList2() + { + UsingStatement(@"void M(__arglist!!) { }", options: TestOptions.RegularPreview, + // (1,17): error CS1003: Syntax error, ',' expected + // void M(__arglist!!) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(1, 17)); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ArgListKeyword); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void TestNullCheckedArgList3() + { + UsingStatement(@"void M(__arglist!! = null) { }", options: TestOptions.RegularPreview, + // (1,17): error CS1003: Syntax error, ',' expected + // void M(__arglist!! = null) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(1, 17)); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ArgListKeyword); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void TestNullCheckedArgList4() + { + UsingStatement(@"void M(__arglist!!= null) { }", options: TestOptions.RegularPreview, + // (1,17): error CS1003: Syntax error, ',' expected + // void M(__arglist!!= null) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(1, 17)); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ArgListKeyword); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void TestNullCheckedArgList5() + { + UsingStatement(@"void M(__arglist[]!!= null) { }", options: TestOptions.RegularPreview, + // (1,17): error CS1003: Syntax error, ',' expected + // void M(__arglist[]!!= null) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "[").WithArguments(",", "[").WithLocation(1, 17), + // (1,18): error CS1001: Identifier expected + // void M(__arglist[]!!= null) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "]").WithLocation(1, 18), + // (1,19): error CS1031: Type expected + // void M(__arglist[]!!= null) { } + Diagnostic(ErrorCode.ERR_TypeExpected, "!").WithLocation(1, 19), + // (1,19): error CS1001: Identifier expected + // void M(__arglist[]!!= null) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "!").WithLocation(1, 19)); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ArgListKeyword); + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + M(SyntaxKind.Attribute); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.CloseBracketToken); + } + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.ExclamationExclamationToken); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + [Fact] public void TestArgListWithBrackets() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs index 1def593ae29a7..05b97c89855da 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs @@ -57,6 +57,146 @@ public void TestInterpolatedVerbatimString() EOF(); } + [Fact] + public void TestInterpolatedSingleLineRawString1() + { + UsingExpression(@"$""""""{1 + 1}"""""""); + N(SyntaxKind.InterpolatedStringExpression); + { + N(SyntaxKind.InterpolatedSingleLineRawStringStartToken); + N(SyntaxKind.Interpolation); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + N(SyntaxKind.PlusToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.InterpolatedRawStringEndToken); + } + EOF(); + } + + [Fact] + public void TestInterpolatedSingleLineRawString2() + { + UsingExpression(@"$$""""""{{{1 + 1}}}"""""""); + N(SyntaxKind.InterpolatedStringExpression); + { + N(SyntaxKind.InterpolatedSingleLineRawStringStartToken); + N(SyntaxKind.InterpolatedStringText); + { + N(SyntaxKind.InterpolatedStringTextToken); + } + N(SyntaxKind.Interpolation); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + N(SyntaxKind.PlusToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.InterpolatedStringText); + { + N(SyntaxKind.InterpolatedStringTextToken); + } + N(SyntaxKind.InterpolatedRawStringEndToken); + } + EOF(); + } + + [Fact] + public void TestInterpolatedMultiLineRawString1() + { + UsingExpression(@"$"""""" + {1 + 1} + """""""); + N(SyntaxKind.InterpolatedStringExpression); + { + N(SyntaxKind.InterpolatedMultiLineRawStringStartToken); + N(SyntaxKind.InterpolatedStringText); + { + N(SyntaxKind.InterpolatedStringTextToken); + } + N(SyntaxKind.Interpolation); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + N(SyntaxKind.PlusToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.InterpolatedRawStringEndToken); + } + EOF(); + } + + [Fact] + public void TestInterpolatedMultiLineRawString2() + { + UsingExpression(@"$$"""""" + {{{1 + 1}}} + """""""); + N(SyntaxKind.InterpolatedStringExpression); + { + N(SyntaxKind.InterpolatedMultiLineRawStringStartToken); + N(SyntaxKind.InterpolatedStringText); + { + N(SyntaxKind.InterpolatedStringTextToken); + } + N(SyntaxKind.Interpolation); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + N(SyntaxKind.PlusToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.InterpolatedStringText); + { + N(SyntaxKind.InterpolatedStringTextToken); + } + N(SyntaxKind.InterpolatedRawStringEndToken); + } + EOF(); + } + [Fact] public void TestAltInterpolatedVerbatimString_CSharp73() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/InterpolatedStringExpressionTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/InterpolatedStringExpressionTests.cs new file mode 100644 index 0000000000000..7d9d6886c3cb0 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/InterpolatedStringExpressionTests.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Parsing; + +public class InterpolatedStringExpressionTests +{ + [Fact] + public void APIBackCompatTest1() + { + Assert.Equal("$\"\"", SyntaxFactory.InterpolatedStringExpression(SyntaxFactory.Token(SyntaxKind.InterpolatedStringStartToken)).ToFullString()); + } + + [Fact] + public void APIBackCompatTest2() + { + Assert.Equal("$\"goo\"", SyntaxFactory.InterpolatedStringExpression( + SyntaxFactory.Token(SyntaxKind.InterpolatedStringStartToken), + SyntaxFactory.SingletonList( + SyntaxFactory.InterpolatedStringText(SyntaxFactory.Token( + default, SyntaxKind.InterpolatedStringTextToken, "goo", "goo", default)))).ToFullString()); + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/InterpolationTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/InterpolationTests.cs new file mode 100644 index 0000000000000..6ba3419ebfb8b --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/InterpolationTests.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 Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Parsing; + +public class InterpolationTests +{ + [Fact] + public void APIBackCompatTest1() + { + Assert.Equal("{a}", SyntaxFactory.Interpolation(SyntaxFactory.IdentifierName("a")).ToFullString()); + } + + [Fact] + public void APIBackCompatTest2() + { + Assert.Equal("{a,b:c}", SyntaxFactory.Interpolation( + SyntaxFactory.IdentifierName("a"), + SyntaxFactory.InterpolationAlignmentClause( + SyntaxFactory.Token(SyntaxKind.CommaToken), + SyntaxFactory.IdentifierName("b")), + SyntaxFactory.InterpolationFormatClause( + SyntaxFactory.Token(SyntaxKind.ColonToken), + SyntaxFactory.Token(default, SyntaxKind.InterpolatedStringTextToken, "c", "c", default))).ToFullString()); + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs index 3ab00d619c16f..bdc4962c818c9 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs @@ -2060,9 +2060,9 @@ public void TestDefaultValueSimpleLambda() public void TestDefaultValueParenthesizedLambda1() { UsingDeclaration("Func func0 = (x = null) => x;", options: TestOptions.RegularPreview, - // (1,41): error CS1003: Syntax error, ',' expected - // Func func0 = (x = null) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 41)); + // (1,33): error CS1065: Default values are not valid in this context. + // Func func0 = (x = null) => x; + Diagnostic(ErrorCode.ERR_DefaultValueNotAllowed, "=").WithLocation(1, 33)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2091,22 +2091,22 @@ public void TestDefaultValueParenthesizedLambda1() N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.ParenthesizedExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.SimpleAssignmentExpression); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { N(SyntaxKind.IdentifierToken, "x"); } - N(SyntaxKind.EqualsToken); - N(SyntaxKind.NullLiteralExpression); - { - N(SyntaxKind.NullKeyword); - } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); } - N(SyntaxKind.CloseParenToken); } } } @@ -2120,9 +2120,9 @@ public void TestDefaultValueParenthesizedLambda1() public void TestDefaultValueParenthesizedLambda2() { UsingDeclaration("Func func0 = (y, x = null) => x;", options: TestOptions.RegularPreview, - // (1,44): error CS1003: Syntax error, ',' expected + // (1,36): error CS1065: Default values are not valid in this context. // Func func0 = (y, x = null) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 44)); + Diagnostic(ErrorCode.ERR_DefaultValueNotAllowed, "=").WithLocation(1, 36)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2151,33 +2151,27 @@ public void TestDefaultValueParenthesizedLambda2() N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.TupleExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Argument); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { N(SyntaxKind.IdentifierToken, "y"); } - } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Argument); - { - N(SyntaxKind.SimpleAssignmentExpression); + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "x"); - } - N(SyntaxKind.EqualsToken); - N(SyntaxKind.NullLiteralExpression); - { - N(SyntaxKind.NullKeyword); - } + N(SyntaxKind.IdentifierToken, "x"); } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); } - N(SyntaxKind.CloseParenToken); } } } @@ -2191,15 +2185,9 @@ public void TestDefaultValueParenthesizedLambda2() public void TestDefaultValueParenthesizedLambdaWithType1() { UsingDeclaration("Func func0 = (string x = null) => x;", options: TestOptions.RegularPreview, - // (1,31): error CS1525: Invalid expression term 'string' + // (1,40): error CS1065: Default values are not valid in this context. // Func func0 = (string x = null) => x; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 31), - // (1,38): error CS1026: ) expected - // Func func0 = (string x = null) => x; - Diagnostic(ErrorCode.ERR_CloseParenExpected, "x").WithLocation(1, 38), - // (1,38): error CS1003: Syntax error, ',' expected - // Func func0 = (string x = null) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 38)); + Diagnostic(ErrorCode.ERR_DefaultValueNotAllowed, "=").WithLocation(1, 40)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2228,14 +2216,26 @@ public void TestDefaultValueParenthesizedLambdaWithType1() N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.ParenthesizedExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.PredefinedType); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.StringKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); } - M(SyntaxKind.CloseParenToken); } } } @@ -2249,15 +2249,9 @@ public void TestDefaultValueParenthesizedLambdaWithType1() public void TestDefaultValueParenthesizedLambdaWithType2() { UsingDeclaration("Func func0 = (string y, string x = null) => x;", options: TestOptions.RegularPreview, - // (1,41): error CS1525: Invalid expression term 'string' - // Func func0 = (string y, string x = null) => x; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 41), - // (1,48): error CS1026: ) expected - // Func func0 = (string y, string x = null) => x; - Diagnostic(ErrorCode.ERR_CloseParenExpected, "x").WithLocation(1, 48), - // (1,48): error CS1003: Syntax error, ',' expected + // (1,50): error CS1065: Default values are not valid in this context. // Func func0 = (string y, string x = null) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 48)); + Diagnostic(ErrorCode.ERR_DefaultValueNotAllowed, "=").WithLocation(1, 50)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2286,32 +2280,35 @@ public void TestDefaultValueParenthesizedLambdaWithType2() N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.TupleExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Argument); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.DeclarationExpression); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { N(SyntaxKind.PredefinedType); { N(SyntaxKind.StringKeyword); } - N(SyntaxKind.SingleVariableDesignation); + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); { - N(SyntaxKind.IdentifierToken, "y"); + N(SyntaxKind.StringKeyword); } + N(SyntaxKind.IdentifierToken, "x"); } + N(SyntaxKind.CloseParenToken); } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Argument); + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.StringKeyword); - } + N(SyntaxKind.IdentifierToken, "x"); } - M(SyntaxKind.CloseParenToken); } } } @@ -2388,9 +2385,9 @@ public void TestNullCheckedDefaultValueSimpleLambda() public void TestNullCheckedDefaultValueParenthesizedLambda1() { UsingDeclaration("Func func0 = (x!! = null) => x;", options: TestOptions.RegularPreview, - // (1,43): error CS1003: Syntax error, ',' expected + // (1,35): error CS1065: Default values are not valid in this context. // Func func0 = (x!! = null) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 43)); + Diagnostic(ErrorCode.ERR_DefaultValueNotAllowed, "=").WithLocation(1, 35)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2419,30 +2416,23 @@ public void TestNullCheckedDefaultValueParenthesizedLambda1() N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.ParenthesizedExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.SimpleAssignmentExpression); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.SuppressNullableWarningExpression); - { - N(SyntaxKind.SuppressNullableWarningExpression); - { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "x"); - } - N(SyntaxKind.ExclamationToken); - } - N(SyntaxKind.ExclamationToken); - } - N(SyntaxKind.EqualsToken); - N(SyntaxKind.NullLiteralExpression); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.NullKeyword); + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.ExclamationExclamationToken); } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); } - N(SyntaxKind.CloseParenToken); } } } @@ -2456,9 +2446,9 @@ public void TestNullCheckedDefaultValueParenthesizedLambda1() public void TestNullCheckedDefaultValueParenthesizedLambda2() { UsingDeclaration("Func func0 = (y, x!! = null) => x;", options: TestOptions.RegularPreview, - // (1,46): error CS1003: Syntax error, ',' expected + // (1,38): error CS1065: Default values are not valid in this context. // Func func0 = (y, x!! = null) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 46)); + Diagnostic(ErrorCode.ERR_DefaultValueNotAllowed, "=").WithLocation(1, 38)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2487,41 +2477,28 @@ public void TestNullCheckedDefaultValueParenthesizedLambda2() N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.TupleExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Argument); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { N(SyntaxKind.IdentifierToken, "y"); } - } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Argument); - { - N(SyntaxKind.SimpleAssignmentExpression); + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.SuppressNullableWarningExpression); - { - N(SyntaxKind.SuppressNullableWarningExpression); - { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "x"); - } - N(SyntaxKind.ExclamationToken); - } - N(SyntaxKind.ExclamationToken); - } - N(SyntaxKind.EqualsToken); - N(SyntaxKind.NullLiteralExpression); - { - N(SyntaxKind.NullKeyword); - } + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.ExclamationExclamationToken); } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); } - N(SyntaxKind.CloseParenToken); } } } @@ -2535,15 +2512,9 @@ public void TestNullCheckedDefaultValueParenthesizedLambda2() public void TestNullCheckedDefaultValueParenthesizedLambdaWithType1() { UsingDeclaration("Func func0 = (string x!! = null) => x;", options: TestOptions.RegularPreview, - // (1,31): error CS1525: Invalid expression term 'string' + // (1,42): error CS1065: Default values are not valid in this context. // Func func0 = (string x!! = null) => x; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 31), - // (1,38): error CS1026: ) expected - // Func func0 = (string x!! = null) => x; - Diagnostic(ErrorCode.ERR_CloseParenExpected, "x").WithLocation(1, 38), - // (1,38): error CS1003: Syntax error, ',' expected - // Func func0 = (string x!! = null) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 38)); + Diagnostic(ErrorCode.ERR_DefaultValueNotAllowed, "=").WithLocation(1, 42)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2572,14 +2543,27 @@ public void TestNullCheckedDefaultValueParenthesizedLambdaWithType1() N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.ParenthesizedExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.PredefinedType); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.StringKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.ExclamationExclamationToken); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); } - M(SyntaxKind.CloseParenToken); } } } @@ -2593,15 +2577,9 @@ public void TestNullCheckedDefaultValueParenthesizedLambdaWithType1() public void TestNullCheckedDefaultValueParenthesizedLambdaWithType2() { UsingDeclaration("Func func0 = (string y, string x!! = null) => x;", options: TestOptions.RegularPreview, - // (1,41): error CS1525: Invalid expression term 'string' - // Func func0 = (string y, string x!! = null) => x; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string").WithLocation(1, 41), - // (1,48): error CS1026: ) expected - // Func func0 = (string y, string x!! = null) => x; - Diagnostic(ErrorCode.ERR_CloseParenExpected, "x").WithLocation(1, 48), - // (1,48): error CS1003: Syntax error, ',' expected - // Func func0 = (string y, string x!! = null) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 48)); + // (1,52): error CS1065: Default values are not valid in this context. + // Func func0 = (string y, string x!! = null) => x; + Diagnostic(ErrorCode.ERR_DefaultValueNotAllowed, "=").WithLocation(1, 52)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2630,32 +2608,36 @@ public void TestNullCheckedDefaultValueParenthesizedLambdaWithType2() N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.TupleExpression); + N(SyntaxKind.ParenthesizedLambdaExpression); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Argument); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.DeclarationExpression); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { N(SyntaxKind.PredefinedType); { N(SyntaxKind.StringKeyword); } - N(SyntaxKind.SingleVariableDesignation); + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); { - N(SyntaxKind.IdentifierToken, "y"); + N(SyntaxKind.StringKeyword); } + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.ExclamationExclamationToken); } + N(SyntaxKind.CloseParenToken); } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Argument); + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.StringKeyword); - } + N(SyntaxKind.IdentifierToken, "x"); } - M(SyntaxKind.CloseParenToken); } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralCompilingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralCompilingTests.cs new file mode 100644 index 0000000000000..38c8f54ab2149 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralCompilingTests.cs @@ -0,0 +1,1861 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Parsing; + +public class RawInterpolatedStringLiteralCompilingTests : CompilingTestBase +{ + private static string Render(string markup, string? normalizedNewLine) + { + markup = markup.Replace('␠', ' ').Replace('␉', '\t'); + + // If we're normalizing newlines, convert everything to \n, then convert that to the newline form asked for. + if (normalizedNewLine != null) + { + markup = markup.Replace("\r\n", "\n"); + markup = markup.Replace("\r", "\n"); + markup = markup.Replace("\n", normalizedNewLine); + } + + return markup; + } + + private void RenderAndVerify(string markup, string expectedOutput) + { + RenderAndVerify(markup, expectedOutput, normalize: null); + RenderAndVerify(markup, expectedOutput, normalize: "\r\n"); + RenderAndVerify(markup, expectedOutput, normalize: "\n"); + RenderAndVerify(markup, expectedOutput, normalize: "\r"); + } + + private void RenderAndVerify(string markup, string expectedOutput, string? normalize) + { + var text = Render(markup, normalize); + ParseAllPrefixes(text); + CompileAndVerify(text, expectedOutput: Render(expectedOutput, normalize), trimOutput: false); + } + + private static void RenderAndVerify(string markup, params DiagnosticDescription[] expected) + { + RenderAndVerify(markup, expected, normalize: null); + RenderAndVerify(markup, expected, normalize: "\r\n"); + RenderAndVerify(markup, expected, normalize: "\n"); + RenderAndVerify(markup, expected, normalize: "\r"); + } + + private static void RenderAndVerify(string markup, DiagnosticDescription[] expected, string? normalize) + { + var text = Render(markup, normalize); + ParseAllPrefixes(text); + CreateCompilation(text).VerifyDiagnostics(expected); + } + + private static void ParseAllPrefixes(string text) + { + // ensure the parser doesn't crash on any test cases. + for (var i = 0; i < text.Length; i++) + SyntaxFactory.ParseCompilationUnit(text[0..^i]); + } + + [Fact] + public void TestDownlevel() + { + CreateCompilation( +@"class C +{ + 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)); + } + + [Fact] + public void TestAtLevel() + { + CreateCompilation( +@"class C +{ + const string s = $"""""" """"""; +}", parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + } + + [Fact] + public void TestInFieldInitializer() + { + CreateCompilation( +@"class C +{ + string s = $"""""" """"""; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInConstantFieldInitializer1() + { + CreateCompilation( +@"class C +{ + const string s = $"""""" """"""; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInConstantFieldInitializer2() + { + CreateCompilation( +@"class C +{ + const string s = $"""""" """""" + ""a""; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInConstantFieldInitializer3() + { + CreateCompilation( +@"class C +{ + const string s = ""a"" + $"""""" """"""; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInConstantFieldInitializer4() + { + CreateCompilation( +@"class C +{ + const string x = ""bar""; + const string s = $""""""{x}""""""; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInAttribute() + { + CreateCompilation( +@" +[System.Obsolete($""""""obsolete"""""")] +class C +{ +}").VerifyDiagnostics(); + } + + [Fact] + public void TestMemberAccess() + { + CreateCompilation( +@"class C +{ + int s = $"""""" """""".Length; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInSwitch() + { + CreateCompilation( +@"class C +{ + void M(string s) + { + switch (s) + { + case $"""""" a """""": + case $"""""" b """""": + break; + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestReachableSwitchCase1() + { + CreateCompilation( +@"class C +{ + void M() + { + switch ($"""""" a """""") + { + case $"""""" a """""": + break; + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestReachableSwitchCase2() + { + CreateCompilation( +@"class C +{ + void M() + { + switch ($"""""" a """""") + { + case $"""""""" a """""""": + break; + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestUnreachableSwitchCase1() + { + CreateCompilation( +@"class C +{ + void M() + { + switch ($"""""" a """""") + { + case $"""""""" b """""""": + break; + } + } +}").VerifyDiagnostics( + // (8,17): warning CS0162: Unreachable code detected + // break; + Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 17)); + } + + [Fact] + public void TestSingleLineRawLiteralInSingleLineInterpolatedString() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $""{$""""""a""""""}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestSingleLineRawLiteralInMultiLineInterpolatedString1() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $@""{$""""""a""""""}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestSingleLineRawLiteralInMultiLineInterpolatedString2() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $@""{ + $""""""a"""""" + }""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestMultiLineRawLiteralInSingleLineInterpolatedString_CSharp9() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $""{$"""""" + +""""""}""; + } +}", 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)); + } + + [Fact] + public void TestMultiLineRawLiteralInSingleLineInterpolatedString_CSharp10() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $""{$"""""" + +""""""}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestMultiLineRawLiteralInMultiLineInterpolatedString1() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $@""{$"""""" + +""""""}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestMultiLineRawLiteralInMultiLineInterpolatedString2() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $@""{ +$"""""" + +"""""" +}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestSingleLineRawLiteralContainingClosingBraceInSingleLineInterpolatedString() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $""{$""""""}""""""}""; + } +}").VerifyDiagnostics( + // (5,24): error CS9007: Too many closing braces for raw string literal + // var v = $"{$"""}"""}"; + Diagnostic(ErrorCode.ERR_TooManyCloseBracesForRawString, "}").WithLocation(5, 24)); + } + + [Fact] + public void TestAwaitRawStringLiteral() + { + CreateCompilation( +@" +using System.Threading.Tasks; + +class C +{ + async Task M() + { + var v = await $"""""" """"""; + } +}").VerifyDiagnostics( + // (8,17): error CS1061: 'string' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) + // var v = await $""" """; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, @"await $"""""" """"""").WithArguments("string", "GetAwaiter").WithLocation(8, 17)); + } + + [Fact] + public void TestInIsConstant() + { + CreateCompilation( +@" +class C +{ + void M(object o) + { + if (o is $"""""" """""") + { + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInIsTuple() + { + CreateCompilation( +@" +class C +{ + void M((string s, int i) o) + { + if (o is ($"""""" """""", 1)) + { + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInSubpattern() + { + CreateCompilation( +@" +class C +{ + string x = """"; + void M(C c) + { + if (c is { x: $"""""" """""" }) + { + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInConditionalExpression() + { + CreateCompilation( +@" +class C +{ + void M(bool b) + { + var x = b ? $"""""" """""" : "" ""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInExpressionStatement() + { + CreateCompilation( +@" +class C +{ + void M(bool b) + { + $"""""" """"""; + } +}").VerifyDiagnostics( + // (6,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // """ """; + Diagnostic(ErrorCode.ERR_IllegalStatement, @"$"""""" """"""").WithLocation(6, 9)); + } + + [Fact] + public void TestInAnonymousObject() + { + CreateCompilation( +@" +class C +{ + void M() + { + var v = new { P = $"""""" """""" }; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInParameterDefault() + { + CreateCompilation( +@"class C +{ + public void M(string s = $"""""" """""") { } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestAttemptingMarkdownInspiredLanguageHint() + { + RenderAndVerify(@" +System.Console.Write( + $""""""xml + + """""");", + // (3,11): error CS8997: Unterminated raw string literal + // $"""xml + Diagnostic(ErrorCode.ERR_UnterminatedRawString, "l").WithLocation(3, 11), + // (4,6): error CS0103: The name 'hi' does not exist in the current context + // + Diagnostic(ErrorCode.ERR_NameNotInContext, "hi").WithArguments("hi").WithLocation(4, 6), + // (4,9): error CS1525: Invalid expression term '>' + // + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ">").WithArguments(">").WithLocation(4, 9), + // (5,10): error CS8997: Unterminated raw string literal + // """); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, "").WithLocation(5, 10), + // (5,10): error CS1026: ) expected + // """); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(5, 10), + // (5,10): error CS1002: ; expected + // """); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(5, 10)); + } + + [Fact] + public void TestAttemptingCommentOnStartingQuoteLine() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" // lang=xml + + """""");", + // (3,20): error CS8997: Unterminated raw string literal + // $""" // lang=xml + Diagnostic(ErrorCode.ERR_UnterminatedRawString, "l").WithLocation(3, 20), + // (4,6): error CS0103: The name 'hi' does not exist in the current context + // + Diagnostic(ErrorCode.ERR_NameNotInContext, "hi").WithArguments("hi").WithLocation(4, 6), + // (4,9): error CS1525: Invalid expression term '>' + // + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ">").WithArguments(">").WithLocation(4, 9), + // (5,10): error CS8997: Unterminated raw string literal + // """); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, "").WithLocation(5, 10), + // (5,10): error CS1026: ) expected + // """); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(5, 10), + // (5,10): error CS1002: ; expected + // """); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(5, 10)); + } + + [Fact] + public void TestInterpolatingAnonymousObject() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + {new { }} + """""");", expectedOutput: "{ }"); + } + + [Fact] + public void TestSingleLineWithWhitespaceAndContent() + { + RenderAndVerify(@" +System.Console.Write($"""""" abc""def """""");", expectedOutput: @" abc""def "); + } + + [Fact] + public void TestSingleLineDiagnosticLocationWithTrivia1() + { + RenderAndVerify(@" +System.Console.Write( +#nullable disable +/**/$""""""{{""""""/**/ +#nullable enable +);", + // (4,9): error CS9006: The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content + // /**/$"""{{"""/**/ + Diagnostic(ErrorCode.ERR_TooManyOpenBracesForRawString, "{").WithLocation(4, 9), + // (4,11): error CS1733: Expected expression + // /**/$"""{{"""/**/ + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(4, 11)); + } + + [Fact] + public void TestSingleLineDiagnosticLocationWithTrivia2() + { + RenderAndVerify(@" +System.Console.Write( +#nullable disable +/**/$""""""}""""""/**/ +#nullable enable +);", + // (4,9): error CS9007: The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content + // /**/$"""}"""/**/ + Diagnostic(ErrorCode.ERR_TooManyCloseBracesForRawString, "}").WithLocation(4, 9)); + } + + [Fact] + public void TestSingleLineDiagnosticLocationWithTrivia3() + { + RenderAndVerify(@" +System.Console.Write( +#nullable disable +/**/$""""""""""""/**/ +#nullable enable +);", + // (4,15): error CS8997: Unterminated raw string literal + // /**/$""""""/**/ + Diagnostic(ErrorCode.ERR_UnterminatedRawString, "/").WithLocation(4, 15)); + } + + [Fact] + public void TestMultiLineDiagnosticLocationWithTrivia1() + { + RenderAndVerify(@" +System.Console.Write( +#nullable disable +/**/$"""""" + {{ + """"""/**/ +#nullable enable +);", + // (5,5): error CS9006: The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive opening braces as content + // {{ + Diagnostic(ErrorCode.ERR_TooManyOpenBracesForRawString, "{").WithLocation(5, 5), + // (6,5): error CS1733: Expected expression + // """/**/ + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 5)); + } + + [Fact] + public void TestMultiLineDiagnosticLocationWithTrivia2() + { + RenderAndVerify(@" +System.Console.Write( +#nullable disable +/**/$"""""" + } + """"""/**/ +#nullable enable +);", + // (5,5): error CS9007: The interpolated raw string literal does not start with enough '$' characters to allow this many consecutive closing braces as content. + // } + Diagnostic(ErrorCode.ERR_TooManyCloseBracesForRawString, "}").WithLocation(5, 5)); + } + + [Fact] + public void TestMultiLineDiagnosticLocationWithTrivia3() + { + RenderAndVerify(@" +System.Console.Write( +#nullable disable +/**/$"""""" + """"""/**/ +#nullable enable +);", + // (5,5): error CS9002: Multi-line raw string literals must contain at least one line of content. + // """/**/ + Diagnostic(ErrorCode.ERR_RawStringMustContainContent, @"""""""").WithLocation(5, 5)); + } + + [Fact] + public void TestPreprocessorConditionInMultilineContent() + { + RenderAndVerify(@" +System.Console.Write( +$"""""" +#if DEBUG +a +#endif +"""""");", expectedOutput: @"#if DEBUG +a +#endif"); + } + + [Fact] + public void TestPreprocessorConditionInInterpolation() + { + RenderAndVerify(@" +System.Console.Write( +$"""""" +{ +#if DEBUG +42 +#endif +} +"""""");", + // (4,2): error CS1073: Unexpected token '#' + // { + Diagnostic(ErrorCode.ERR_UnexpectedToken, "").WithArguments("#").WithLocation(4, 2), + // (5,1): error CS1003: Syntax error, '}' expected + // #if DEBUG + Diagnostic(ErrorCode.ERR_SyntaxError, "#").WithArguments("}").WithLocation(5, 1), + // (5,1): error CS1525: Invalid expression term '' + // #if DEBUG + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "#").WithArguments("").WithLocation(5, 1), + // (5,1): error CS1056: Unexpected character '#' + // #if DEBUG + Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("#").WithLocation(5, 1), + // (7,1): error CS1056: Unexpected character '#' + // #endif + Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("#").WithLocation(7, 1)); + } + + [Fact] + public void TestTrivia() + { + RenderAndVerify(@" +System.Console.Write( +$"""""" +{ +#if DEBUG +42 +#endif +} +"""""");", + // (4,2): error CS1073: Unexpected token '#' + // { + Diagnostic(ErrorCode.ERR_UnexpectedToken, "").WithArguments("#").WithLocation(4, 2), + // (5,1): error CS1003: Syntax error, '}' expected + // #if DEBUG + Diagnostic(ErrorCode.ERR_SyntaxError, "#").WithArguments("}").WithLocation(5, 1), + // (5,1): error CS1525: Invalid expression term '' + // #if DEBUG + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "#").WithArguments("").WithLocation(5, 1), + // (5,1): error CS1056: Unexpected character '#' + // #if DEBUG + Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("#").WithLocation(5, 1), + // (7,1): error CS1056: Unexpected character '#' + // #endif + Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("#").WithLocation(7, 1)); + } + + [Fact] + public void TestSingleLineOutput1() + { + CompileAndVerify( +@" +using System; + +class C +{ + static void Main() + { + Console.Write($""""""abc""def""""""); + } +}", expectedOutput: @"abc""def"); + } + + [Fact] + public void TestSingleLineOutput2() + { + CompileAndVerify( +@" +using System; + +Console.Write($""""""abc""def""""""); +", expectedOutput: @"abc""def"); + } + + [Fact] + public void TestMultiLineOutput1() + { + CompileAndVerify( +@" +using System; + +class C +{ + static void Main() + { + Console.Write($"""""" + abc"" + def + """"""); + } +}".Replace("\r\n", "\n"), expectedOutput: "abc\"\ndef"); + } + + [Fact] + public void TestMultiLineOutput2() + { + CompileAndVerify( +@" +using System; + +class C +{ + static void Main() + { + Console.Write( + $"""""" + abc"" + def + """"""); + } +}".Replace("\r\n", "\n"), expectedOutput: " abc\"\n def"); + } + + [Fact] + public void MultiLineCase01() + { + RenderAndVerify(@" +System.Console.Write( + $"""""");", + // (3,10): error CS8997: Unterminated raw string literal + // $"""); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(3, 10), + // (3,11): error CS1026: ) expected + // $"""); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(3, 11), + // (3,11): error CS1002: ; expected + // $"""); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(3, 11)); + } + + [Fact] + public void MultiLineCase02() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + "");", + // (4,7): error CS8997: Unterminated raw string literal + // "); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 7), + // (4,8): error CS1026: ) expected + // "); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 8), + // (4,8): error CS1002: ; expected + // "); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 8)); + } + + [Fact] + public void MultiLineCase03() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + """");", + // (4,8): error CS8997: Unterminated raw string literal + // ""); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 8), + // (4,9): error CS1026: ) expected + // ""); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 9), + // (4,9): error CS1002: ; expected + // ""); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 9)); + } + + [Fact] + public void MultiLineCase04() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + """""");", + // (4,5): error CS9002: Multi-line raw string literals must contain at least one line of content + // """); + Diagnostic(ErrorCode.ERR_RawStringMustContainContent, @"""""""").WithLocation(4, 5)); + } + + [Fact] + public void MultiLineCase05() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + + """""");", expectedOutput: ""); + } + + [Fact] + public void MultiLineCase06() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠ + "");", + // (4,7): error CS8997: Unterminated raw string literal + // "); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 7), + // (4,8): error CS1026: ) expected + // "); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 8), + // (4,8): error CS1002: ; expected + // "); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 8)); + } + + [Fact] + public void MultiLineCase07() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠ + """");", + // (4,8): error CS8997: Unterminated raw string literal + // ""); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 8), + // (4,9): error CS1026: ) expected + // ""); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 9), + // (4,9): error CS1002: ; expected + // ""); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 9)); + } + + [Fact] + public void MultiLineCase08() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠ + """""");", + // (4,5): error CS9002: Multi-line raw string literals must contain at least one line of content + // """); + Diagnostic(ErrorCode.ERR_RawStringMustContainContent, @"""""""").WithLocation(4, 5)); + } + + [Fact] + public void MultiLineCase09() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠ + + """""");", expectedOutput: ""); + } + + [Fact] + public void MultiLineCase10() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + "");", + // (4,7): error CS8997: Unterminated raw string literal + // "); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 7), + // (4,8): error CS1026: ) expected + // "); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 8), + // (4,8): error CS1002: ; expected + // "); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 8)); + } + + [Fact] + public void MultiLineCase11() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + """");", + // (4,8): error CS8997: Unterminated raw string literal + // ""); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 8), + // (4,9): error CS1026: ) expected + // ""); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 9), + // (4,9): error CS1002: ; expected + // ""); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 9)); + } + + [Fact] + public void MultiLineCase12() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + """""");", + // (4,5): error CS9002: Multi-line raw string literals must contain at least one line of content + // """); + Diagnostic(ErrorCode.ERR_RawStringMustContainContent, @"""""""").WithLocation(4, 5)); + } + + [Fact] + public void MultiLineCase13() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + + """""");", expectedOutput: ""); + } + + [Fact] + public void MultiLineCase14() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + ␠"");", + // (4,8): error CS8997: Unterminated raw string literal + // "); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 8), + // (4,9): error CS1026: ) expected + // "); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 9), + // (4,9): error CS1002: ; expected + // "); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 9)); + } + + [Fact] + public void MultiLineCase15() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + ␠"""");", + // (4,9): error CS8997: Unterminated raw string literal + // ""); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 9), + // (4,10): error CS1026: ) expected + // ""); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 10), + // (4,10): error CS1002: ; expected + // ""); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 10)); + } + + [Fact] + public void MultiLineCase16() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠ + ␠"""");", + // (4,9): error CS8997: Unterminated raw string literal + // ""); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 9), + // (4,10): error CS1026: ) expected + // ""); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 10), + // (4,10): error CS1002: ; expected + // ""); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 10)); + } + + [Fact] + public void MultiLineCase17() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + ␠␠"""");", + // (4,10): error CS8997: Unterminated raw string literal + // ""); + Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(4, 10), + // (4,11): error CS1026: ) expected + // ""); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 11), + // (4,11): error CS1002: ; expected + // ""); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 11)); + } + + [Fact] + public void MultiLineCase18() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + ␠␠"""""");", + // (4,7): error CS9002: Multi-line raw string literals must contain at least one line of content + // """); + Diagnostic(ErrorCode.ERR_RawStringMustContainContent, @"""""""").WithLocation(4, 7)); + } + + [Fact] + public void MultiLineCase19() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + + ␠␠"""""");", expectedOutput: ""); + } + + [Fact] + public void MultiLineCase20() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + a"" + """""");", expectedOutput: "a\""); + } + + [Fact] + public void MultiLineCase21() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + a"""" + """""");", expectedOutput: "a\"\""); + } + + [Fact] + public void MultiLineCase22() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + ""a + """""");", expectedOutput: "\"a"); + } + + [Fact] + public void MultiLineCase23() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + """"a + """""");", expectedOutput: "\"\"a"); + } + + [Fact] + public void MultiLineCase24() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + a"""""");", + // (4,6): error CS9000: Raw string literal delimiter must be on its own line + // a"""); + Diagnostic(ErrorCode.ERR_RawStringDelimiterOnOwnLine, @"""""""").WithLocation(4, 6)); + } + + [Fact] + public void MultiLineCase25() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + a"""""""");", + // (4,6): error CS9000: Raw string literal delimiter must be on its own line + // a""""); + Diagnostic(ErrorCode.ERR_RawStringDelimiterOnOwnLine, @"""""""""").WithLocation(4, 6)); + } + + [Fact] + public void MultiLineCase26() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + a + """""");", expectedOutput: "a"); + } + + [Fact] + public void MultiLineCase27() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + ␠a + """""");", expectedOutput: " a"); + } + + [Fact] + public void MultiLineCase28() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + a␠ + """""");", expectedOutput: "a "); + } + + [Fact] + public void MultiLineCase29() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + ␠a␠ + """""");", expectedOutput: " a "); + } + + [Fact] + public void MultiLineCase30() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + a + """""""");", + // (5,8): error CS8998: Too many closing quotes for raw string literal + // """"); + Diagnostic(ErrorCode.ERR_TooManyQuotesForRawString, @"""").WithLocation(5, 8)); + } + + [Fact] + public void MultiLineCase31() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + a + """""""""");", + // (5,8): error CS8998: Too many closing quotes for raw string literal + // """""); + Diagnostic(ErrorCode.ERR_TooManyQuotesForRawString, @"""""").WithLocation(5, 8)); + } + + [Fact] + public void MultiLineCase32() + { + RenderAndVerify(@" +System.Console.Write( + $""""""␠␠ + a + """""""""""");", + // (5,4): error CS8998: Too many closing quotes for raw string literal + // """"""); + Diagnostic(ErrorCode.ERR_TooManyQuotesForRawString, @"""""""").WithLocation(5, 8)); + } + + [Fact] + public void MultiLineCase33() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + {42} + b + {43} + c + """""");", + // (4,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // a + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(4, 1)); + } + + [Fact] + public void MultiLineCase34() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + {42} + b + {43} + c + """""");", + // (5,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // {42} + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(5, 1)); + } + + [Fact] + public void MultiLineCase35() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + {42} + b + {43} + c + """""");", + // (6,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // b + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(6, 1)); + } + + [Fact] + public void MultiLineCase36() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + {42} + b + {43} + c + """""");", + // (7,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // {43} + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(7, 1)); + } + + [Fact] + public void MultiLineCase37() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + {42} + b + {43} + c + """""");", + // (8,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // c + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(8, 1)); + } + + [Fact] + public void MultiLineCase38() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + aa + {42} + b + {43} + c + """""");", + // (5,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // aa + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(5, 1)); + } + + [Fact] + public void MultiLineCase39() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + {42} + {42} + b + {43} + c + """""");", + // (6,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // {42} + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(6, 1)); + } + + [Fact] + public void MultiLineCase40() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + {42} + b + bb + {43} + c + """""");", + // (7,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // bb + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(7, 1)); + } + + [Fact] + public void MultiLineCase41() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + {42} + b + {43} + {43} + c + """""");", + // (8,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // {43} + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(8, 1)); + } + + [Fact] + public void MultiLineCase42() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + {42} + b + {43} + c + cc + """""");", + // (9,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // cc + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(9, 1)); + } + + [Fact] + public void MultiLineCase43() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + {42}a{43} + """""");", expectedOutput: "42a43"); + } + + [Fact] + public void MultiLineCase44() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + {42}a + + a{43} + """""");", expectedOutput: @"42a + +a43"); + } + + [Fact] + public void MultiLineCase45() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + {42}a +␠ + a{43} + """""");", expectedOutput: @"42a + +a43"); + } + + [Fact] + public void MultiLineCase46() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + {42}a +␠␠␠␠␠ + a{43} + """""");", expectedOutput: @"42a +␠ +a43"); + } + + [Fact] + public void MultiLineCase47() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + {42}a + b + + b + a{43} + """""");", expectedOutput: @"42a +b + +b +a43"); + } + + [Fact] + public void MultiLineCase48() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + {42}a + b +␠ + b + a{43} + """""");", expectedOutput: @"42a +b + +b +a43"); + } + + [Fact] + public void MultiLineCase49() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + {42}a + b +␠␠␠␠␠ + b + a{43} + """""");", expectedOutput: @"42a +b +␠ +b +a43"); + } + + [Fact] + public void MultiLineCase50() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + + a + {42} + b + b + a{43} + c + c + """""");", expectedOutput: @"a + +a +42 +b +b +a43 +c +c"); + } + + [Fact] + public void MultiLineCase51() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a +␠ + a + {42} + b + b + a{43} + c + c + """""");", expectedOutput: @"a + +a +42 +b +b +a43 +c +c"); + } + + [Fact] + public void MultiLineCase52() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a +␠␠␠␠␠ + a + {42} + b + b + a{43} + c + c + """""");", expectedOutput: @"a +␠ +a +42 +b +b +a43 +c +c"); + } + + [Fact] + public void MultiLineCase53() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a +␠a + a + {42} + b + b + a{43} + c + c + """""");", + // (5,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // a + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(5, 1)); + } + + [Fact] + public void MultiLineCase54() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + a + {42} + b + b + a{43} + c +␠ + c + """""");", expectedOutput: @"a +a +42 +b +b +a43 +c + +c"); + } + + [Fact] + public void MultiLineCase55() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + a + {42} + b + b + a{43} + c +␠␠␠␠␠ + c + """""");", expectedOutput: @"a +a +42 +b +b +a43 +c +␠ +c"); + } + + [Fact] + public void MultiLineCase56() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + a + {42} + b + b + a{43} + c +␠c + c + """""");", + // (11,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // c + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(11, 1)); + } + + [Fact] + public void MultiLineCase57() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + + """""");", expectedOutput: ""); + } + + [Fact] + public void MultiLineCase58() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" +␠ + """""");", expectedOutput: ""); + } + + [Fact] + public void MultiLineCase59() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" +␠␠ + """""");", expectedOutput: ""); + } + + [Fact] + public void MultiLineCase60() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" +␠␠␠␠ + """""");", expectedOutput: ""); + } + + [Fact] + public void MultiLineCase61() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" +␠␠␠␠␠ + """""");", expectedOutput: "␠"); + } + + [Fact] + public void MultiLineCase62() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a + + """""");", expectedOutput: @"a +"); + } + + [Fact] + public void MultiLineCase63() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a +␠ + """""");", expectedOutput: @"a +"); + } + + [Fact] + public void MultiLineCase64() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a +␠␠ + """""");", expectedOutput: @"a +"); + } + + [Fact] + public void MultiLineCase65() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a +␠␠␠␠ + """""");", expectedOutput: @"a +"); + } + + [Fact] + public void MultiLineCase66() + { + RenderAndVerify(@" +System.Console.Write( + $"""""" + a +␠␠␠␠␠ + """""");", expectedOutput: @"a +␠"); + } + + [Fact] + public void TestOutVarOrderOfEvaluation1() + { + CompileAndVerify( +@" +using System; + +Console.Write($""""""{M(out var x)} {x}""""""); + +int M(out int val) +{ + val = 2; + return 1; +} +", expectedOutput: @"1 2"); + } + + [Fact] + public void TestOutVarOrderOfEvaluation2() + { + RenderAndVerify( +@" +using System; + +Console.Write($""""""{x} {M(out var x)}""""""); + +int M(out int val) +{ + val = 2; + return 1; +} +", + // (4,20): error CS0841: Cannot use local variable 'x' before it is declared + // Console.Write($"""{x} {M(out var x)}"""); + Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x").WithArguments("x").WithLocation(4, 20)); + } + + + [Fact] + public void TestWhitespaceMismatch1() + { + RenderAndVerify( +"class C\r\n{\r\nconst string s = $\"\"\"\r\n\t\r\n \"\"\";\r\n}", + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\t' versus '\u0020' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\t", @"\u0020").WithLocation(4, 1)); + } + + [Fact] + public void TestWhitespaceMismatch2() + { + RenderAndVerify( +"class C\r\n{\r\nconst string s = $\"\"\"\r\n \r\n\t\"\"\";\r\n}", + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\u0020' versus '\t' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\u0020", @"\t").WithLocation(4, 1)); + } + + [Fact] + public void TestWhitespaceMismatch3() + { + RenderAndVerify( +"class C\r\n{\r\nconst string s = $\"\"\"\r\n \t\r\n \"\"\";\r\n}", + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\t' versus '\u0020' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\t", @"\u0020").WithLocation(4, 1)); + } + + [Fact] + public void TestWhitespaceMismatch4() + { + RenderAndVerify( +"class C\r\n{\r\nconst string s = $\"\"\"\r\n \t\r\n \"\"\";\r\n}", + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\t' versus '\u0020' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\t", @"\u0020").WithLocation(4, 1)); + } + + [Fact] + public void TestWhitespaceMismatch5() + { + RenderAndVerify( +"class C\r\n{\r\nconst string s = $\"\"\"\r\n\f\r\n\v\"\"\";\r\n}", + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\f' versus '\v' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\f", @"\v").WithLocation(4, 1)); + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralParsingTests.cs new file mode 100644 index 0000000000000..800637d83691d --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RawInterpolatedStringLiteralParsingTests.cs @@ -0,0 +1,1870 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Parsing; + +public class RawInterpolatedStringLiteralParsingTests : CSharpTestBase +{ + #region Single Line + + [Fact] + public void SingleLine1() + { + var text = @" +class C +{ + void M() + { + var v = $"""""" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineTooManyCloseQuotes1() + { + var text = @" +class C +{ + void M() + { + var v = $"""""" """"""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,25): error CS8998: Too many closing quotes for raw string literal + // var v = $""" """"; + Diagnostic(ErrorCode.ERR_TooManyQuotesForRawString, @"""").WithLocation(6, 25)); + } + + [Fact] + public void SingleLineTooManyCloseQuotes2() + { + var text = @" +class C +{ + void M() + { + var v = $"""""" """"""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,25): error CS8998: Too many closing quotes for raw string literal + // var v = $""" """""; + Diagnostic(ErrorCode.ERR_TooManyQuotesForRawString, @"""""").WithLocation(6, 25)); + } + + [Fact] + public void SingleLineSingleQuoteInside() + { + var text = @" +class C +{ + void M() + { + var v = $"""""" "" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineDoubleQuoteInside() + { + var text = @" +class C +{ + void M() + { + var v = $"""""" """" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationInside() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{0}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationInsideSpacesOutside() + { + var text = @" +class C +{ + void M() + { + var v = $"""""" {0} """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationInsideSpacesInside() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{ 0 }""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationInsideSpacesInsideAndOutside() + { + var text = @" +class C +{ + void M() + { + var v = $"""""" { 0 } """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationMultipleCurliesNotAllowed1() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{{0}}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,21): error CS9006: Too many open braces for raw string literal + // var v = $"""{{0}}"""; + Diagnostic(ErrorCode.ERR_TooManyOpenBracesForRawString, "{").WithLocation(6, 21)); + } + + [Fact] + public void SingleLineInterpolationMultipleCurliesNotAllowed2() + { + var text = @" +class C +{ + void M() + { + var v = $$""""""{{{{0}}}}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,22): error CS9006: Too many open braces for raw string literal + // var v = $$"""{{{{0}}}}"""; + Diagnostic(ErrorCode.ERR_TooManyOpenBracesForRawString, "{{").WithLocation(6, 22)); + } + + [Fact] + public void SingleLineInterpolationMultipleCurliesNotAllowed3() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{0}}}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,24): error CS9007: Too many closing braces for raw string literal + // var v = $"""{0}}}"""; + Diagnostic(ErrorCode.ERR_TooManyCloseBracesForRawString, "}}").WithLocation(6, 24)); + } + + [Fact] + public void SingleLineInterpolationMultipleCurliesNotAllowed4() + { + var text = @" +class C +{ + void M() + { + var v = $$""""""{{{0}}}}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,28): error CS9007: Too many closing braces for raw string literal + // var v = $$"""{{{0}}}}"""; + Diagnostic(ErrorCode.ERR_TooManyCloseBracesForRawString, "}}").WithLocation(6, 28)); + } + + [Fact] + public void SingleLineInterpolationMultipleCurliesNotAllowed5() + { + var text = @" +class C +{ + void M() + { + var v = $$""""""{0}}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,24): error CS9007: Too many closing braces for raw string literal + // var v = $$"""{0}}"""; + Diagnostic(ErrorCode.ERR_TooManyCloseBracesForRawString, "}}").WithLocation(6, 24)); + } + + [Fact] + public void SingleLineInterpolationMultipleCurliesNotAllowed6() + { + var text = @" +class C +{ + void M() + { + var v = $$""""""{{{0}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,22): error CS9005: Not enough closing braces for raw string literal + // var v = $$"""{{{0}"""; + Diagnostic(ErrorCode.ERR_NotEnoughCloseBracesForRawString, "{").WithLocation(6, 22)); + } + + [Fact] + public void SingleLineInterpolationMultipleCurliesAllowed1() + { + var text = @" +class C +{ + void M() + { + var v = $$""""""{{0}}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationMultipleCurliesAllowed2() + { + var text = @" +class C +{ + void M() + { + var v = $$""""""{{{0}}}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationMultipleCurliesAllowed4() + { + var text = @" +class C +{ + void M() + { + var v = $$""""""{{{0}}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingNormalString() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{""a""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingVerbatimString1() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{@""a""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingVerbatimString2() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{@"" +a""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingInterpolatedString1() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""a""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingInterpolatedString2() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""{0}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingVerbatimInterpolatedString1() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$@""{0}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingVerbatimInterpolatedString2() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{@$""{0}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingVerbatimInterpolatedString3() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$@""{ +0}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingVerbatimInterpolatedString4() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{ +$@""{ +0}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawStringLiteral1() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{""""""a""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawStringLiteral2() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{"""""" + a + """"""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawStringLiteral3() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{"""""" + a + """"""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (7,1): error CS8999: Line does not start with the same whitespace as the closing line of the raw string literal + // a + Diagnostic(ErrorCode.ERR_LineDoesNotStartWithSameWhitespace, " ").WithLocation(7, 1)); + } + + [Fact] + public void SingleLineInterpolationContainingRawInterpolatedStringLiteral1() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$"""""" """"""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawInterpolatedStringLiteral2() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$"""""""" """"""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawInterpolatedStringLiteral3() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""""""{0}""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawInterpolatedStringLiteral4() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""""""{ +0}""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawInterpolatedStringLiteral5() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{ +$""""""{ +0}""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawInterpolatedStringLiteral6() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$$""""""{{0}}""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawInterpolatedStringLiteral7() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$$""""""{{{0}}}""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingRawInterpolatedStringLiteral8() + { + var text = @" +class C +{ + void M() + { + var v = $$""""""{{{$""""""{0}""""""}}}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingClosingBraceAsCharacterLiteral() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{'}'}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingClosingBraceAsRegularStringLiteral() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{""}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingClosingBraceAsVerbatimStringLiteral() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{@""}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void SingleLineInterpolationContainingClosingBraceAsRawStringLiteral() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{""""""}""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterNormalMiddleNormalInnerNormal() + { + var text = @" +class C +{ + void M() + { + var v = $""{$""{$""{0}""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterNormalMiddleNormalInnerVerbatim() + { + var text = @" +class C +{ + void M() + { + var v = $""{$""{$@""{0}""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterNormalMiddleNormalInnerRaw() + { + var text = @" +class C +{ + void M() + { + var v = $""{$""{$""""""{0}""""""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterNormalMiddleVerbatimInnerNormal() + { + var text = @" +class C +{ + void M() + { + var v = $""{@$""{$""{0}""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterNormalMiddleVerbatimInnerVerbatim() + { + var text = @" +class C +{ + void M() + { + var v = $""{@$""{@$""{0}""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterNormalMiddleVerbatimInnerRaw() + { + var text = @" +class C +{ + void M() + { + var v = $""{@$""{$""""""{0}""""""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterNormalMiddleRawInnerNormal() + { + var text = @" +class C +{ + void M() + { + var v = $""{$""""""{$""{0}""}""""""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterNormalMiddleRawInnerVerbatim() + { + var text = @" +class C +{ + void M() + { + var v = $""{$""""""{@$""{0}""}""""""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterNormalMiddleRawInnerRaw() + { + var text = @" +class C +{ + void M() + { + var v = $""{$""""""{$""""""{0}""""""}""""""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterVerbatimMiddleNormalInnerNormal() + { + var text = @" +class C +{ + void M() + { + var v = $@""{$""{$""{0}""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterVerbatimMiddleNormalInnerVerbatim() + { + var text = @" +class C +{ + void M() + { + var v = $@""{$""{$@""{0}""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterVerbatimMiddleNormalInnerRaw() + { + var text = @" +class C +{ + void M() + { + var v = $@""{$""{$""""""{0}""""""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterVerbatimMiddleVerbatimInnerNormal() + { + var text = @" +class C +{ + void M() + { + var v = $@""{@$""{$""{0}""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterVerbatimMiddleVerbatimInnerVerbatim() + { + var text = @" +class C +{ + void M() + { + var v = $@""{@$""{@$""{0}""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterVerbatimMiddleVerbatimInnerRaw() + { + var text = @" +class C +{ + void M() + { + var v = $@""{@$""{$""""""{0}""""""}""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterVerbatimMiddleRawInnerNormal() + { + var text = @" +class C +{ + void M() + { + var v = $@""{$""""""{$""{0}""}""""""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterVerbatimMiddleRawInnerVerbatim() + { + var text = @" +class C +{ + void M() + { + var v = $@""{$""""""{@$""{0}""}""""""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterVerbatimMiddleRawInnerRaw() + { + var text = @" +class C +{ + void M() + { + var v = $@""{$""""""{$""""""{0}""""""}""""""}""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterRawMiddleNormalInnerNormal() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""{$""{0}""}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterRawMiddleNormalInnerVerbatim() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""{$@""{0}""}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterRawMiddleNormalInnerRaw() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""{$""""""{0}""""""}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterRawMiddleVerbatimInnerNormal() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{@$""{$""{0}""}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterRawMiddleVerbatimInnerVerbatim() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{@$""{@$""{0}""}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterRawMiddleVerbatimInnerRaw() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{@$""{$""""""{0}""""""}""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterRawMiddleRawInnerNormal() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""""""{$""{0}""}""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterRawMiddleRawInnerVerbatim() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""""""{@$""{0}""}""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void OuterRawMiddleRawInnerRaw() + { + var text = @" +class C +{ + void M() + { + var v = $""""""{$""""""{$""""""{0}""""""}""""""}""""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics(); + } + + [Fact] + public void MultipleAtSigns1() + { + var text = @" +class C +{ + void M() + { + var v = @@; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS1525: Invalid expression term '' + // var v = @@; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "@@").WithArguments("").WithLocation(6, 17), + // (6,17): error CS1646: Keyword, identifier, or string expected after verbatim specifier: @ + // var v = @@; + Diagnostic(ErrorCode.ERR_ExpectedVerbatimLiteral, "").WithLocation(6, 17)); + } + + [Fact] + public void MultipleAtSigns2() + { + var text = @" +class C +{ + void M() + { + var v = @@""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9008: Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + // var v = @@"; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, "@@").WithLocation(6, 17), + // (6,17): error CS1039: Unterminated string literal + // var v = @@"; + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "").WithLocation(6, 17), + // (8,2): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(8, 2), + // (8,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(8, 2), + // (8,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(8, 2)); + } + + [Fact] + public void MultipleAtSigns3() + { + var text = @" +class C +{ + void M() + { + var v = @@"" ""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9008: Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + // var v = @@" "; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, "@@").WithLocation(6, 17)); + } + + [Fact] + public void MultipleAtSigns4() + { + var text = @" +class C +{ + void M() + { + var v = @@"""""" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9008: Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + // var v = @@""" """; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, "@@").WithLocation(6, 17)); + } + + [Fact] + public void MultipleAtSigns5() + { + var text = @" +class C +{ + void M() + { + var v = @@@; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS1525: Invalid expression term '' + // var v = @@@; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "@@@").WithArguments("").WithLocation(6, 17), + // (6,17): error CS1646: Keyword, identifier, or string expected after verbatim specifier: @ + // var v = @@@; + Diagnostic(ErrorCode.ERR_ExpectedVerbatimLiteral, "").WithLocation(6, 17)); + } + + [Fact] + public void MultipleAtSigns6() + { + var text = @" +class C +{ + void M() + { + var v = @@@""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9008: Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + // var v = @@@"; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, "@@@").WithLocation(6, 17), + // (6,17): error CS1039: Unterminated string literal + // var v = @@@"; + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "").WithLocation(6, 17), + // (8,2): error CS1002: ; expected + // } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(8, 2), + // (8,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(8, 2), + // (8,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(8, 2)); + } + + [Fact] + public void MultipleAtSigns7() + { + var text = @" +class C +{ + void M() + { + var v = @@@"" ""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9008: Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + // var v = @@@" "; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, "@@@").WithLocation(6, 17)); + } + + [Fact] + public void MultipleAtSigns8() + { + var text = @" +class C +{ + void M() + { + var v = @@@"""""" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9008: Sequence of '@' characters is not allowed. A verbatim string or identifier can only have one '@' character and a raw string cannot have any. + // var v = @@@""" """; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, "@@@").WithLocation(6, 17)); + } + + [Fact] + public void DollarThenAt1() + { + var text = @" +class C +{ + void M() + { + var v = $@@; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: String must start with quote character: " + // var v = $@@; + Diagnostic(ErrorCode.ERR_StringMustStartWithQuoteCharacter, "$@@").WithLocation(6, 17)); + } + + [Fact] + public void DollarThenAt2() + { + var text = @" +class C +{ + void M() + { + var v = $@@""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = $@@"; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"$@@""").WithLocation(6, 17), + // (6,22): error CS1002: ; expected + // var v = $@@"; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 22)); + } + + [Fact] + public void DollarThenAt3() + { + var text = @" +class C +{ + void M() + { + var v = $@@"" ""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = $@@" "; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"$@@""").WithLocation(6, 17)); + } + + [Fact] + public void DollarThenAt4() + { + var text = @" +class C +{ + void M() + { + var v = $@@"""""" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = $@@""" """; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"$@@""""""").WithLocation(6, 17)); + } + + [Fact] + public void DollarThenAt5() + { + var text = @" +class C +{ + void M() + { + var v = $@@@; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: String must start with quote character: " + // var v = $@@@; + Diagnostic(ErrorCode.ERR_StringMustStartWithQuoteCharacter, "$@@@").WithLocation(6, 17)); + } + + [Fact] + public void DollarThenAt6() + { + var text = @" +class C +{ + void M() + { + var v = $@@@""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = $@@@"; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"$@@@""").WithLocation(6, 17), + // (6,23): error CS1002: ; expected + // var v = $@@@"; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 23)); + } + + [Fact] + public void DollarThenAt7() + { + var text = @" +class C +{ + void M() + { + var v = $@@@"" ""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = $@@@" "; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"$@@@""").WithLocation(6, 17)); + } + + [Fact] + public void DollarThenAt8() + { + var text = @" +class C +{ + void M() + { + var v = $@@@"""""" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = $@@@""" """; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"$@@@""""""").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollar1() + { + var text = @" +class C +{ + void M() + { + var v = @@$; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: String must start with quote character: " + // var v = @@$; + Diagnostic(ErrorCode.ERR_StringMustStartWithQuoteCharacter, "@@$").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollar2() + { + var text = @" +class C +{ + void M() + { + var v = @@$""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$"; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$""").WithLocation(6, 17), + // (6,22): error CS1002: ; expected + // var v = @@$"; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 22)); + } + + [Fact] + public void AtThenDollar3() + { + var text = @" +class C +{ + void M() + { + var v = @@$"" ""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$" "; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$""").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollar4() + { + var text = @" +class C +{ + void M() + { + var v = @@$"""""" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$""" """; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$""""""").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollar5() + { + var text = @" +class C +{ + void M() + { + var v = @@$$; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: String must start with quote character: " + // var v = @@$$; + Diagnostic(ErrorCode.ERR_StringMustStartWithQuoteCharacter, "@@$$").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollar6() + { + var text = @" +class C +{ + void M() + { + var v = @@$$""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$$"; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$$""").WithLocation(6, 17), + // (6,23): error CS1002: ; expected + // var v = @@$$"; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 23)); + } + + [Fact] + public void AtThenDollar7() + { + var text = @" +class C +{ + void M() + { + var v = @@$$"" ""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$$" "; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$$""").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollar8() + { + var text = @" +class C +{ + void M() + { + var v = @@$$"""""" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$$""" """; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$$""""""").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollarThenAt1() + { + var text = @" +class C +{ + void M() + { + var v = @@$@; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: String must start with quote character: " + // var v = @@$@; + Diagnostic(ErrorCode.ERR_StringMustStartWithQuoteCharacter, "@@$@").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollarThenAt2() + { + var text = @" +class C +{ + void M() + { + var v = @@$@""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$@"; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$@""").WithLocation(6, 17), + // (6,23): error CS1002: ; expected + // var v = @@$@"; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 23)); + } + + [Fact] + public void AtThenDollarThenAt3() + { + var text = @" +class C +{ + void M() + { + var v = @@$@"" ""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$@" "; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$@""").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollarThenAt4() + { + var text = @" +class C +{ + void M() + { + var v = @@$@"""""" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$@""" """; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$@""""""").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollarThenAt5() + { + var text = @" +class C +{ + void M() + { + var v = @@$$@; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: String must start with quote character: " + // var v = @@$$@; + Diagnostic(ErrorCode.ERR_StringMustStartWithQuoteCharacter, "@@$$@").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollarThenAt6() + { + var text = @" +class C +{ + void M() + { + var v = @@$$@""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$$@"; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$$@""").WithLocation(6, 17), + // (6,24): error CS1002: ; expected + // var v = @@$$@"; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 24)); + } + + [Fact] + public void AtThenDollarThenAt7() + { + var text = @" +class C +{ + void M() + { + var v = @@$$@"" ""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$$@" "; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$$@""").WithLocation(6, 17)); + } + + [Fact] + public void AtThenDollarThenAt8() + { + var text = @" +class C +{ + void M() + { + var v = @@$$@"""""" """"""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: Cannot mix verbatim and raw strings + // var v = @@$$@""" """; + Diagnostic(ErrorCode.ERR_IllegalAtSequence, @"@@$$@""""""").WithLocation(6, 17)); + } + + [Fact] + public void DollarsWithoutQuotes0() + { + var text = @" +class C +{ + void M() + { + var v = $; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS1525: Invalid expression term '' + // var v = $; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "$").WithArguments("").WithLocation(6, 17), + // (6,17): error CS1056: Unexpected character '$' + // var v = $; + Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("$").WithLocation(6, 17)); + } + + [Fact] + public void DollarsWithoutQuotes1() + { + var text = @" +class C +{ + void M() + { + var v = $$; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: String must start with quote character: " + // var v = $$; + Diagnostic(ErrorCode.ERR_StringMustStartWithQuoteCharacter, "$$").WithLocation(6, 17)); + } + + [Fact] + public void DollarsWithoutQuotes2() + { + var text = @" +class C +{ + void M() + { + var v = $$$; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,17): error CS9009: String must start with quote character: " + // var v = $$$; + Diagnostic(ErrorCode.ERR_StringMustStartWithQuoteCharacter, "$$$").WithLocation(6, 17)); + } + + [Fact] + public void DollarsWithQuotes1() + { + var text = @" +class C +{ + void M() + { + var v = $$""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,19): error CS9004: Not enough quotes for raw string literal + // var v = $$"; + Diagnostic(ErrorCode.ERR_NotEnoughQuotesForRawString, @"""").WithLocation(6, 19), + // (6,21): error CS1002: ; expected + // var v = $$"; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 21)); + } + + [Fact] + public void DollarsWithQuotes2() + { + var text = @" +class C +{ + void M() + { + var v = $$"" ""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,19): error CS9004: Not enough quotes for raw string literal + // var v = $$" "; + Diagnostic(ErrorCode.ERR_NotEnoughQuotesForRawString, @"""").WithLocation(6, 19)); + } + + [Fact] + public void DollarsWithQuotes3() + { + var text = @" +class C +{ + void M() + { + var v = $$"""" """"; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,19): error CS9004: Not enough quotes for raw string literal + // var v = $$"" ""; + Diagnostic(ErrorCode.ERR_NotEnoughQuotesForRawString, @"""""").WithLocation(6, 19)); + } + + #endregion + + #region Multi Line + + [Fact] + public void DollarsWithQuotes2_MultiLine() + { + var text = @" +class C +{ + void M() + { + var v = $$"" + +""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,19): error CS9004: Not enough quotes for raw string literal + // var v = $$" + Diagnostic(ErrorCode.ERR_NotEnoughQuotesForRawString, @"""").WithLocation(6, 19)); + } + + [Fact] + public void DollarsWithQuotes3_MultiLine() + { + var text = @" +class C +{ + void M() + { + var v = $$"""" + +""""; + } +}"; + + CreateCompilation(text).VerifyDiagnostics( + // (6,19): error CS9004: Not enough quotes for raw string literal + // var v = $$"" + Diagnostic(ErrorCode.ERR_NotEnoughQuotesForRawString, @"""""").WithLocation(6, 19)); + } + + #endregion +} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RawStringLiteralCompilingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RawStringLiteralCompilingTests.cs new file mode 100644 index 0000000000000..ebefc81bf7f87 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RawStringLiteralCompilingTests.cs @@ -0,0 +1,529 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Parsing; + +public class RawStringLiteralCompilingTests : CompilingTestBase +{ + [Fact] + public void TestDownlevel() + { + CreateCompilation( +@"class C +{ + 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)); + } + + [Fact] + public void TestInFieldInitializer() + { + CreateCompilation( +@"class C +{ + string s = """""" """"""; +}").VerifyDiagnostics( + // (3,12): warning CS0414: The field 'C.s' is assigned but its value is never used + // string s = """ """; + Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "s").WithArguments("C.s").WithLocation(3, 12)); + } + + [Fact] + public void TestInConstantFieldInitializer1() + { + CreateCompilation( +@"class C +{ + const string s = """""" """"""; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInConstantFieldInitializer2() + { + CreateCompilation( +@"class C +{ + const string s = """""" """""" + ""a""; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInConstantFieldInitializer3() + { + CreateCompilation( +@"class C +{ + const string s = ""a"" + """""" """"""; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInAttribute() + { + CreateCompilation( +@" +[System.Obsolete(""""""obsolete"""""")] +class C +{ +}").VerifyDiagnostics(); + } + + [Fact] + public void TestMemberAccess() + { + CreateCompilation( +@"class C +{ + int s = """""" """""".Length; +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInSwitch() + { + CreateCompilation( +@"class C +{ + void M(string s) + { + switch (s) + { + case """""" a """""": + case """""" b """""": + break; + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestReachableSwitchCase1() + { + CreateCompilation( +@"class C +{ + void M() + { + switch ("""""" a """""") + { + case """""" a """""": + break; + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestReachableSwitchCase2() + { + CreateCompilation( +@"class C +{ + void M() + { + switch ("""""" a """""") + { + case """""""" a """""""": + break; + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestUnreachableSwitchCase1() + { + CreateCompilation( +@"class C +{ + void M() + { + switch ("""""" a """""") + { + case """""""" b """""""": + break; + } + } +}").VerifyDiagnostics( + // (8,17): warning CS0162: Unreachable code detected + // break; + Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 17)); + } + + [Fact] + public void TestSingleLineRawLiteralInSingleLineInterpolatedString() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $""{""""""a""""""}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestSingleLineRawLiteralInMultiLineInterpolatedString1() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $@""{""""""a""""""}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestSingleLineRawLiteralInMultiLineInterpolatedString2() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $@""{ + """"""a"""""" + }""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestMultiLineRawLiteralInSingleLineInterpolatedString_CSharp9() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $""{"""""" + +""""""}""; + } +}", 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)); + } + + [Fact] + public void TestMultiLineRawLiteralInSingleLineInterpolatedString_CSharp10() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $""{"""""" + +""""""}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestMultiLineRawLiteralInMultiLineInterpolatedString1() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $@""{"""""" + +""""""}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestMultiLineRawLiteralInMultiLineInterpolatedString2() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $@""{ +"""""" + +"""""" +}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestSingleLineRawLiteralContainingClosingBraceInSingleLineInterpolatedString() + { + CreateCompilation( +@"class C +{ + void M() + { + var v = $""{""""""}""""""}""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestAwaitRawStringLiteral() + { + CreateCompilation( +@" +using System.Threading.Tasks; + +class C +{ + async Task M() + { + var v = await """""" """"""; + } +}").VerifyDiagnostics( + // (8,17): error CS1061: 'string' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) + // var v = await """ """; + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, @"await """""" """"""").WithArguments("string", "GetAwaiter").WithLocation(8, 17)); + } + + [Fact] + public void TestInIsConstant() + { + CreateCompilation( +@" +class C +{ + void M(object o) + { + if (o is """""" """""") + { + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInIsTuple() + { + CreateCompilation( +@" +class C +{ + void M((string s, int i) o) + { + if (o is ("""""" """""", 1)) + { + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInSubpattern() + { + CreateCompilation( +@" +class C +{ + string x = """"; + void M(C c) + { + if (c is { x: """""" """""" }) + { + } + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInConditionalExpression() + { + CreateCompilation( +@" +class C +{ + void M(bool b) + { + var x = b ? """""" """""" : "" ""; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestInExpressionStatement() + { + CreateCompilation( +@" +class C +{ + void M(bool b) + { + """""" """"""; + } +}").VerifyDiagnostics( + // (6,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // """ """; + Diagnostic(ErrorCode.ERR_IllegalStatement, @""""""" """"""").WithLocation(6, 9)); + } + + [Fact] + public void TestInAnonymousObject() + { + CreateCompilation( +@" +class C +{ + void M() + { + var v = new { P = """""" """""" }; + } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestSingleLineOutput1() + { + CompileAndVerify( +@" +using System; + +class C +{ + static void Main() + { + Console.WriteLine(""""""abc""def""""""); + } +}", expectedOutput: @"abc""def"); + } + + [Fact] + public void TestSingleLineOutput2() + { + CompileAndVerify( +@" +using System; + +Console.WriteLine(""""""abc""def""""""); +", expectedOutput: @"abc""def"); + } + + [Fact] + public void TestSingleLineOutput3() + { + CompileAndVerify( +@" +using System; + +Console.WriteLine("""""" abc""def """"""); +", expectedOutput: @" abc""def "); + } + + [Fact] + public void TestMultiLineOutput1() + { + CompileAndVerify( +@" +using System; + +class C +{ + static void Main() + { + Console.WriteLine("""""" + abc"" + def + """"""); + } +}".Replace("\r\n", "\n"), expectedOutput: "abc\"\ndef"); + } + + [Fact] + public void TestMultiLineOutput2() + { + CompileAndVerify( +@" +using System; + +class C +{ + static void Main() + { + Console.WriteLine( + """""" + abc"" + def + """"""); + } +}".Replace("\r\n", "\n"), expectedOutput: " abc\"\n def"); + } + + [Fact] + public void TestInParameterDefault() + { + CreateCompilation( +@"class C +{ + public void M(string s = """""" """""") { } +}").VerifyDiagnostics(); + } + + [Fact] + public void TestWhitespaceMismatch1() + { + CreateCompilation( +"class C\r\n{\r\nconst string s = \"\"\"\r\n\t\r\n \"\"\";\r\n}").VerifyDiagnostics( + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\t' versus '\u0020' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\t", @"\u0020").WithLocation(4, 1)); + } + + [Fact] + public void TestWhitespaceMismatch2() + { + CreateCompilation( +"class C\r\n{\r\nconst string s = \"\"\"\r\n \r\n\t\"\"\";\r\n}").VerifyDiagnostics( + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\u0020' versus '\t' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\u0020", @"\t").WithLocation(4, 1)); + } + + [Fact] + public void TestWhitespaceMismatch3() + { + CreateCompilation( +"class C\r\n{\r\nconst string s = \"\"\"\r\n \t\r\n \"\"\";\r\n}").VerifyDiagnostics( + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\t' versus '\u0020' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\t", @"\u0020").WithLocation(4, 1)); + } + + [Fact] + public void TestWhitespaceMismatch4() + { + CreateCompilation( +"class C\r\n{\r\nconst string s = \"\"\"\r\n \t\r\n \"\"\";\r\n}").VerifyDiagnostics( + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\t' versus '\u0020' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\t", @"\u0020").WithLocation(4, 1)); + } + + [Fact] + public void TestWhitespaceMismatch5() + { + CreateCompilation( +"class C\r\n{\r\nconst string s = \"\"\"\r\n\f\r\n\v\"\"\";\r\n}").VerifyDiagnostics( + // (4,1): error CS9003: Line contains different whitespace than the closing line of the raw string literal: '\f' versus '\v' + Diagnostic(ErrorCode.ERR_LineContainsDifferentWhitespace, " ").WithArguments(@"\f", @"\v").WithLocation(4, 1)); + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxEquivalenceTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxEquivalenceTests.cs index 2dcae4aa9babf..c7ec106fc2cfd 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxEquivalenceTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxEquivalenceTests.cs @@ -589,5 +589,78 @@ void M() VerifyNotEquivalent(tree1, tree2, topLevel: true); VerifyNotEquivalent(tree1, tree2, topLevel: false); } + + [Fact] + public void TestRawStringLiteral1() + { + var tree1 = SyntaxFactory.ParseSyntaxTree(@" +class C +{ + void M() + { + var v = """"""abc""""""; + } +}"); + + var tree2 = SyntaxFactory.ParseSyntaxTree(@" +class C +{ + void M() + { + var v = """"""abc""""""; + } +}"); + + VerifyEquivalent(tree1, tree2, topLevel: false); + } + + [Fact] + public void TestRawStringLiteral2() + { + var tree1 = SyntaxFactory.ParseSyntaxTree(@" +class C +{ + void M() + { + var v = """"""abc""""""; + } +}"); + + var tree2 = SyntaxFactory.ParseSyntaxTree(@" +class C +{ + void M() + { + var v = """"""abcd""""""; + } +}"); + + VerifyNotEquivalent(tree1, tree2, topLevel: false); + VerifyEquivalent(tree1, tree2, topLevel: true); + } + + [Fact] + public void TestRawStringLiteral3() + { + var tree1 = SyntaxFactory.ParseSyntaxTree(@" +class C +{ + void M() + { + var v = """"""abc""""""; + } +}"); + + var tree2 = SyntaxFactory.ParseSyntaxTree(@" +class C +{ + void M() + { + var v = ""abc""; + } +}"); + + VerifyNotEquivalent(tree1, tree2, topLevel: false); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs index e5c6579071790..f2f40caaf5cb2 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs @@ -3802,5 +3802,15 @@ public void TestStackAllocKeywordUpdate() var newExpression = expression.Update(replacedKeyword, expression.Type).ToString(); Assert.Equal("stackalloc int[50]", newExpression); } + + [Fact] + [WorkItem(58597, "https://github.com/dotnet/roslyn/issues/58597")] + public void TestExclamationExclamationUpdate() + { + var text = "(string s!!)"; + var parameter = SyntaxFactory.ParseParameterList(text).Parameters[0]; + var newParameter = parameter.Update(parameter.AttributeLists, parameter.Modifiers, parameter.Type, parameter.Identifier, parameter.Default).ToString(); + Assert.Equal("string s!!", newParameter); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs index 1861e0efeaf80..d72a43893e72a 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs @@ -4,13 +4,9 @@ #nullable disable -using System.Text; -using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; +using System; using Roslyn.Test.Utilities; using Xunit; -using System; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -77,6 +73,21 @@ public void TestNormalizeSwitchExpression() ); } + [Fact] + public void TestNormalizeSwitchExpressionRawStrings() + { + TestNormalizeStatement( + @"var x = (int)1 switch { 1 => """"""one"""""", 2 => """"""two"""""", 3 => """"""three"""""", {} => """""">= 4"""""" };", + @"var x = (int)1 switch +{ + 1 => """"""one"""""", + 2 => """"""two"""""", + 3 => """"""three"""""", + { } => """""">= 4"""""" +};".NormalizeLineEndings() + ); + } + [Fact, WorkItem(52543, "https://github.com/dotnet/roslyn/issues/52543")] public void TestNormalizeSwitchRecPattern() { @@ -185,6 +196,16 @@ public void TestLineBreakInterpolations() ); } + [Fact] + public void TestLineBreakRawInterpolations() + { + TestNormalizeExpression( + @"$""""""Printed: { new Printer() { TextToPrint = ""Hello world!"" }.PrintedText }""""""", + @"$""""""Printed: {new Printer() +{TextToPrint = ""Hello world!""}.PrintedText}""""""".Replace("\r\n", "\n").Replace("\n", "\r\n") + ); + } + [Fact, WorkItem(50742, "https://github.com/dotnet/roslyn/issues/50742")] public void TestVerbatimStringInterpolationWithLineBreaks() { @@ -203,6 +224,26 @@ public void TestVerbatimStringInterpolationWithLineBreaks() ); } + [Fact] + public void TestRawStringInterpolationWithLineBreaks() + { + TestNormalizeStatement(@"Console.WriteLine($"""""" + Test with line + breaks + { + new[]{ + 1, 2, 3 + }[2] + } + """""");", + @"Console.WriteLine($"""""" + Test with line + breaks + {new[]{1, 2, 3}[2]} + """""");" + ); + } + [Fact] public void TestNormalizeExpression1() { @@ -595,6 +636,29 @@ public void TestSpacingOnInterpolatedString() TestNormalizeExpression("$\"{3: C}\"", "$\"{3: C}\""); } + [Fact] + public void TestSpacingOnRawInterpolatedString() + { + TestNormalizeExpression("$\"\"\"{3:C}\"\"\"", "$\"\"\"{3:C}\"\"\""); + TestNormalizeExpression("$\"\"\"{3: C}\"\"\"", "$\"\"\"{3: C}\"\"\""); + TestNormalizeExpression("$\"\"\"{3:C }\"\"\"", "$\"\"\"{3:C }\"\"\""); + TestNormalizeExpression("$\"\"\"{3: C }\"\"\"", "$\"\"\"{3: C }\"\"\""); + + TestNormalizeExpression("$\"\"\"{ 3:C}\"\"\"", "$\"\"\"{3:C}\"\"\""); + TestNormalizeExpression("$\"\"\"{ 3: C}\"\"\"", "$\"\"\"{3: C}\"\"\""); + TestNormalizeExpression("$\"\"\"{ 3:C }\"\"\"", "$\"\"\"{3:C }\"\"\""); + TestNormalizeExpression("$\"\"\"{ 3: C }\"\"\"", "$\"\"\"{3: C }\"\"\""); + TestNormalizeExpression("$\"\"\"{3 :C}\"\"\"", "$\"\"\"{3:C}\"\"\""); + TestNormalizeExpression("$\"\"\"{3 : C}\"\"\"", "$\"\"\"{3: C}\"\"\""); + TestNormalizeExpression("$\"\"\"{3 :C }\"\"\"", "$\"\"\"{3:C }\"\"\""); + TestNormalizeExpression("$\"\"\"{3 : C }\"\"\"", "$\"\"\"{3: C }\"\"\""); + + TestNormalizeExpression("$\"\"\"{ 3 :C}\"\"\"", "$\"\"\"{3:C}\"\"\""); + TestNormalizeExpression("$\"\"\"{ 3 : C}\"\"\"", "$\"\"\"{3: C}\"\"\""); + TestNormalizeExpression("$\"\"\"{ 3 :C }\"\"\"", "$\"\"\"{3:C }\"\"\""); + TestNormalizeExpression("$\"\"\"{ 3 : C }\"\"\"", "$\"\"\"{3: C }\"\"\""); + } + [Fact] [WorkItem(23618, "https://github.com/dotnet/roslyn/issues/23618")] public void TestSpacingOnMethodConstraint() @@ -635,6 +699,12 @@ public void TestNormalizeInterpolatedString() TestNormalizeExpression(@"$""Message is {a}""", @"$""Message is {a}"""); } + [Fact] + public void TestNormalizeRawInterpolatedString() + { + TestNormalizeExpression(@"$""""""Message is {a}""""""", @"$""""""Message is {a}"""""""); + } + [WorkItem(528584, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528584")] [Fact] public void TestNormalizeRegion2() @@ -752,6 +822,29 @@ public void TestNormalizeLineDirectiveTrivia() // Note: the literal was formatted as a C# string literal, not as a directive string literal. } + [Fact] + public void TestNormalizeLineSpanDirectiveNode() + { + TestNormalize( + SyntaxFactory.LineSpanDirectiveTrivia( + SyntaxFactory.Token(SyntaxKind.HashToken), + SyntaxFactory.Token(SyntaxKind.LineKeyword), + SyntaxFactory.LineDirectivePosition(SyntaxFactory.Literal(1), SyntaxFactory.Literal(2)), + SyntaxFactory.Token(SyntaxKind.MinusToken), + SyntaxFactory.LineDirectivePosition(SyntaxFactory.Literal(3), SyntaxFactory.Literal(4)), + SyntaxFactory.Literal(5), + SyntaxFactory.Literal("a.txt"), + SyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), + isActive: true), + "#line (1, 2) - (3, 4) 5 \"a.txt\"\r\n"); + } + + [Fact] + public void TestNormalizeLineSpanDirectiveTrivia() + { + TestNormalizeTrivia(" # line( 1,2 )-(3,4)5\"a.txt\"", "#line (1, 2) - (3, 4) 5 \"a.txt\"\r\n"); + } + [WorkItem(538115, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538115")] [Fact] public void TestNormalizeWithinDirectives() diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTests.cs index 303826d9fb679..ce2330c1d7593 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxTests.cs @@ -196,5 +196,48 @@ public void TestIsReservedTupleElementName(string elementName, bool isReserved) { Assert.Equal(isReserved, SyntaxFacts.IsReservedTupleElementName(elementName)); } + + [Theory] + [InlineData(SyntaxKind.StringLiteralToken)] + [InlineData(SyntaxKind.SingleLineRawStringLiteralToken)] + [InlineData(SyntaxKind.MultiLineRawStringLiteralToken)] + [InlineData(SyntaxKind.CharacterLiteralToken)] + [InlineData(SyntaxKind.NumericLiteralToken)] + [InlineData(SyntaxKind.XmlTextLiteralToken)] + [InlineData(SyntaxKind.XmlTextLiteralNewLineToken)] + [InlineData(SyntaxKind.XmlEntityLiteralToken)] + public void TestIsLiteral(SyntaxKind kind) + { + Assert.True(SyntaxFacts.IsLiteral(kind)); + } + + [Theory] + [InlineData(SyntaxKind.StringLiteralToken)] + [InlineData(SyntaxKind.SingleLineRawStringLiteralToken)] + [InlineData(SyntaxKind.MultiLineRawStringLiteralToken)] + [InlineData(SyntaxKind.CharacterLiteralToken)] + [InlineData(SyntaxKind.NumericLiteralToken)] + [InlineData(SyntaxKind.XmlTextLiteralToken)] + [InlineData(SyntaxKind.XmlTextLiteralNewLineToken)] + [InlineData(SyntaxKind.XmlEntityLiteralToken)] + public void TestIsAnyToken(SyntaxKind kind) + { + Assert.True(SyntaxFacts.IsAnyToken(kind)); + } + + [Theory] + [InlineData(SyntaxKind.StringLiteralToken, SyntaxKind.StringLiteralExpression)] + [InlineData(SyntaxKind.SingleLineRawStringLiteralToken, SyntaxKind.StringLiteralExpression)] + [InlineData(SyntaxKind.MultiLineRawStringLiteralToken, SyntaxKind.StringLiteralExpression)] + [InlineData(SyntaxKind.CharacterLiteralToken, SyntaxKind.CharacterLiteralExpression)] + [InlineData(SyntaxKind.NumericLiteralToken, SyntaxKind.NumericLiteralExpression)] + [InlineData(SyntaxKind.NullKeyword, SyntaxKind.NullLiteralExpression)] + [InlineData(SyntaxKind.TrueKeyword, SyntaxKind.TrueLiteralExpression)] + [InlineData(SyntaxKind.FalseKeyword, SyntaxKind.FalseLiteralExpression)] + [InlineData(SyntaxKind.ArgListKeyword, SyntaxKind.ArgListExpression)] + public void TestGetLiteralExpression(SyntaxKind tokenKind, SyntaxKind expressionKind) + { + Assert.Equal(expressionKind, SyntaxFacts.GetLiteralExpression(tokenKind)); + } } } diff --git a/src/Compilers/CSharp/Test/WinRT/CodeGen/WinMdEventTests.cs b/src/Compilers/CSharp/Test/WinRT/CodeGen/WinMdEventTests.cs index 0d9339ad85c34..10b823874e0c7 100644 --- a/src/Compilers/CSharp/Test/WinRT/CodeGen/WinMdEventTests.cs +++ b/src/Compilers/CSharp/Test/WinRT/CodeGen/WinMdEventTests.cs @@ -277,7 +277,7 @@ static void Action() } } "; - var verifier = CompileAndVerifyWithWinRt(source, options: TestOptions.ReleaseWinMD); + var verifier = CompileAndVerifyWithWinRt(source, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseWinMD); verifier.VerifyIL("D.InstanceAdd", @" { @@ -370,7 +370,7 @@ static void Action() } } "; - var verifier = CompileAndVerifyWithWinRt(source, options: TestOptions.ReleaseWinMD); + var verifier = CompileAndVerifyWithWinRt(source, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseWinMD); verifier.VerifyIL("C.InstanceAssign", @" { diff --git a/src/Compilers/Core/CodeAnalysisRules.ruleset b/src/Compilers/Core/CodeAnalysisRules.ruleset deleted file mode 100644 index f705862df1653..0000000000000 --- a/src/Compilers/Core/CodeAnalysisRules.ruleset +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerConfigTests.cs b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerConfigTests.cs index 9e95d03f88395..4ffcc51e6d617 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerConfigTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerConfigTests.cs @@ -2536,6 +2536,29 @@ public void EquivalentSourcePathNames(string sourcePath, bool shouldMatch) } } + + [Fact] + public void CorrectlyMergeGlobalConfigWithEscapedPaths() + { + var configs = ArrayBuilder.GetInstance(); + configs.Add(Parse(@" +is_global = true +[/Test.cs] +a = a +[/\Test.cs] +b = b +", "/.editorconfig")); + + var configSet = AnalyzerConfigSet.Create(configs, out var diagnostics); + configs.Free(); + + var options = configSet.GetOptionsForSourcePath("/Test.cs"); + + Assert.Equal(2, options.AnalyzerOptions.Count); + Assert.Equal("a", options.AnalyzerOptions["a"]); + Assert.Equal("b", options.AnalyzerOptions["b"]); + } + #endregion } } diff --git a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/SuppressMessageAttributeCompilerTests.cs b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/SuppressMessageAttributeCompilerTests.cs index 3ef22bc03355a..9edf099ef6ca4 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/SuppressMessageAttributeCompilerTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/SuppressMessageAttributeCompilerTests.cs @@ -154,13 +154,16 @@ public class C2 public async Task AnalyzerExceptionFromSupportedDiagnosticsCall() { var exception = new Exception(); + const string AnalyzerName = "Microsoft.CodeAnalysis.UnitTests.Diagnostics.SuppressMessageAttributeTests+ThrowExceptionFromSupportedDiagnostics"; var diagnostic = Diagnostic("AD0001", null) .WithArguments( - "Microsoft.CodeAnalysis.UnitTests.Diagnostics.SuppressMessageAttributeTests+ThrowExceptionFromSupportedDiagnostics", + AnalyzerName, "System.Exception", exception.Message, - (IFormattable)$@"{new LazyToString(() => exception.ToString().Substring(0, exception.ToString().IndexOf("---")))}-----") + (IFormattable)$@"{new LazyToString(() => + exception.ToString().Substring(0, exception.ToString().IndexOf("---")) + "-----" + Environment.NewLine + Environment.NewLine + + string.Format(CodeAnalysisResources.CompilerAnalyzerThrowsDescription, AnalyzerName, exception.ToString() + Environment.NewLine + "-----" + Environment.NewLine))}") .WithLocation(1, 1); await VerifyCSharpAsync("public class C { }", diff --git a/src/Compilers/Core/MSBuildTask/Csc.cs b/src/Compilers/Core/MSBuildTask/Csc.cs index 3dead94c8a72b..e08251e95556c 100644 --- a/src/Compilers/Core/MSBuildTask/Csc.cs +++ b/src/Compilers/Core/MSBuildTask/Csc.cs @@ -176,7 +176,7 @@ public string? Nullable // Same separators as those used by Process.OutputDataReceived to maintain consistency between csc and VBCSCompiler private static readonly string[] s_separators = { "\r\n", "\r", "\n" }; - private protected override void LogCompilerOutput(string output, MessageImportance messageImportance) + internal override void LogCompilerOutput(string output, MessageImportance messageImportance) { var lines = output.Split(s_separators, StringSplitOptions.RemoveEmptyEntries); foreach (string line in lines) diff --git a/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs b/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs index b4353e6cc96c3..1b97358743141 100644 --- a/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs +++ b/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs @@ -691,7 +691,10 @@ private int HandleResponse(Guid requestId, BuildResponse? response, string pathT /// in the language specific manner. This often involves parsing the raw output and formatting it as /// individual messages for MSBuild. /// - private protected abstract void LogCompilerOutput(string output, MessageImportance messageImportance); + /// + /// Internal for testing only. + /// + internal abstract void LogCompilerOutput(string output, MessageImportance messageImportance); /// /// Used to log a message that should go into both the compiler server log as well as the MSBuild logs diff --git a/src/Compilers/Core/MSBuildTask/Vbc.cs b/src/Compilers/Core/MSBuildTask/Vbc.cs index f74e830993918..8df24a2e5b34b 100644 --- a/src/Compilers/Core/MSBuildTask/Vbc.cs +++ b/src/Compilers/Core/MSBuildTask/Vbc.cs @@ -238,7 +238,7 @@ public string? PdbFile private static readonly string[] s_separator = { Environment.NewLine }; - private protected override void LogCompilerOutput(string output, MessageImportance messageImportance) + internal override void LogCompilerOutput(string output, MessageImportance messageImportance) { var lines = output.Split(s_separator, StringSplitOptions.None); foreach (string line in lines) @@ -648,12 +648,9 @@ protected override void LogEventsFromTextOutput(string singleLine, MessageImport /// Given a string, parses it to find out whether it's an error or warning and, if so, /// make sure it's validated properly. /// - /// - /// INTERNAL FOR UNITTESTING ONLY - /// /// The line to parse /// The MessageImportance to use when reporting the error. - internal void ParseVBErrorOrWarning(string singleLine, MessageImportance messageImportance) + private void ParseVBErrorOrWarning(string singleLine, MessageImportance messageImportance) { // if this string is empty then we haven't seen the first line of an error yet if (_vbErrorLines.Count > 0) @@ -689,7 +686,7 @@ internal void ParseVBErrorOrWarning(string singleLine, MessageImportance message string originalVBErrorString = originalVBError.Message; int column = singleLine.IndexOf('~') + 1; - int endParenthesisLocation = originalVBErrorString.IndexOf(')'); + int endParenthesisLocation = originalVBErrorString.IndexOf(") :", StringComparison.Ordinal); // If for some reason the line does not contain any ~ then something went wrong // so abort and return the original string. diff --git a/src/Compilers/Core/MSBuildTaskTests/TestUtilities/ErrorLoggerEngine.cs b/src/Compilers/Core/MSBuildTaskTests/TestUtilities/ErrorLoggerEngine.cs new file mode 100644 index 0000000000000..9fa6ca10be8c0 --- /dev/null +++ b/src/Compilers/Core/MSBuildTaskTests/TestUtilities/ErrorLoggerEngine.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Reflection; +using System.Text; +using Microsoft.Build.Framework; + +namespace Microsoft.CodeAnalysis.BuildTasks.UnitTests +{ + /// + /// An engine to output event messages as MSBuild does to test Vbc.ParseVBErrorOrWarning. + /// + internal sealed class ErrorLoggingEngine : IBuildEngine + { + private StringBuilder _log = new StringBuilder(); + public MessageImportance MinimumMessageImportance = MessageImportance.Low; + private readonly MethodInfo _formatErrorMethod; + private readonly MethodInfo _formatWarningMethod; + + public ErrorLoggingEngine() + { + // Use the formatting from Microsoft.Build.Shared.EventArgsFormatting. + var assembly = Assembly.LoadFrom("Microsoft.Build.dll"); + var formattingClass = assembly.GetType("Microsoft.Build.Shared.EventArgsFormatting") ?? throw new Exception("Could not find EventArgsFormatting type"); + _formatErrorMethod = formattingClass.GetMethod("FormatEventMessage", BindingFlags.Static | BindingFlags.NonPublic, null, CallingConventions.Any, + new Type[] { typeof(BuildErrorEventArgs) }, null) ?? throw new Exception("Could not find FormatEventMessage(BuildErrorEventArgs)."); + _formatWarningMethod = formattingClass.GetMethod("FormatEventMessage", BindingFlags.Static | BindingFlags.NonPublic, null, CallingConventions.Any, + new Type[] { typeof(BuildWarningEventArgs) }, null) ?? throw new Exception("Could not find FormatEventMessage(BuildWarningEventArgs)."); + } + + internal string Log + { + set { _log = new StringBuilder(value); } + get { return _log.ToString(); } + } + + public void LogErrorEvent(BuildErrorEventArgs eventArgs) + { + _log.Append(_formatErrorMethod.Invoke(null, new object[] { eventArgs })); + _log.AppendLine(); + } + + public void LogWarningEvent(BuildWarningEventArgs eventArgs) + { + _log.Append(_formatWarningMethod.Invoke(null, new object[] { eventArgs })); + _log.AppendLine(); + } + + public void LogCustomEvent(CustomBuildEventArgs eventArgs) + { + } + + public void LogMessageEvent(BuildMessageEventArgs eventArgs) + { + } + + public string ProjectFileOfTaskNode => ""; + public int ColumnNumberOfTaskNode => 0; + public int LineNumberOfTaskNode => 0; + public bool ContinueOnError => true; + + public bool BuildProjectFile(string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs) + => throw new NotImplementedException(); + + } +} diff --git a/src/Compilers/Core/MSBuildTaskTests/VbcTests.cs b/src/Compilers/Core/MSBuildTaskTests/VbcTests.cs index e118161a64553..f00012c40e0e0 100644 --- a/src/Compilers/Core/MSBuildTaskTests/VbcTests.cs +++ b/src/Compilers/Core/MSBuildTaskTests/VbcTests.cs @@ -464,6 +464,37 @@ public void SkipAnalyzersFlag() Assert.Equal("/optionstrict:custom /out:test.exe test.vb", vbc.GenerateResponseFileContents()); } + [Fact] + [WorkItem(47790, "https://github.com/dotnet/roslyn/issues/47790")] + public void CheckErrorAndWarningParsing() + { + var vbc = new Vbc(); + var engine = new ErrorLoggingEngine(); + vbc.BuildEngine = engine; + // Use reflection to set protected property UsedCommandLineTool to true so Vbc.LogEventsFromTextOutput will pass the messages along to ParseVBErrorOrWarning. + typeof(Vbc).GetProperty("UsedCommandLineTool", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)?.SetValue(vbc, true); + // Errors and warnings were generated by compiling the code used in the test at + // Microsoft.CodeAnalysis.VisualBasic.CommandLine.UnitTests.CommandLineTests.LogErrorsWithColumnNumbers() + vbc.LogCompilerOutput(@" +C:\Test Path (123)\hellovb.vb(6) : warning BC40008: 'Public Property x As Integer' is obsolete. + + x = 3.5 + ~ +C:\Test Path (123)\hellovb.vb(6) : error BC30512: Option Strict On disallows implicit conversions from 'Double' to 'Integer'. + + x = 3.5 + ~~~ +C:\Test Path (123)\hellovb.vb(7) : error BC30451: 'asdf' is not declared. It may be inaccessible due to its protection level. + + asdf + ~~~~ +", Build.Framework.MessageImportance.High); + // Check that the column number is being added at the correct place. + Assert.Contains(@"C:\Test Path (123)\hellovb.vb(6,9): warning BC40008: 'Public Property x As Integer' is obsolete.", engine.Log); + Assert.Contains(@"C:\Test Path (123)\hellovb.vb(6,13): error BC30512: Option Strict On disallows implicit conversions from 'Double' to 'Integer'.", engine.Log); + Assert.Contains(@"C:\Test Path (123)\hellovb.vb(7,9): error BC30451: 'asdf' is not declared. It may be inaccessible due to its protection level.", engine.Log); + } + [Fact] [WorkItem(52467, "https://github.com/dotnet/roslyn/issues/52467")] public void UnexpectedExceptionLogsMessage() diff --git a/src/Compilers/Core/Portable/CaseInsensitiveComparison.cs b/src/Compilers/Core/Portable/CaseInsensitiveComparison.cs index 937429ff7b6b1..865c51408aaf7 100644 --- a/src/Compilers/Core/Portable/CaseInsensitiveComparison.cs +++ b/src/Compilers/Core/Portable/CaseInsensitiveComparison.cs @@ -117,7 +117,7 @@ public override int Compare(string? str1, string? str2) return str1.Length - str2.Length; } -#if !NET20 && !NETSTANDARD1_3 +#if !NET20 public int Compare(ReadOnlySpan str1, ReadOnlySpan str2) { int len = Math.Min(str1.Length, str2.Length); @@ -168,7 +168,7 @@ public override bool Equals(string? str1, string? str2) return true; } -#if !NET20 && !NETSTANDARD1_3 +#if !NET20 public bool Equals(ReadOnlySpan str1, ReadOnlySpan str2) { if (str1.Length != str2.Length) @@ -293,7 +293,7 @@ public override int GetHashCode(string str) /// public static bool Equals(string left, string right) => s_comparer.Equals(left, right); -#if !NET20 && !NETSTANDARD1_3 +#if !NET20 /// /// Determines if two strings are equal according to Unicode rules for case-insensitive /// identifier comparison (lower-case mapping). @@ -335,7 +335,7 @@ public override int GetHashCode(string str) /// public static int Compare(string left, string right) => s_comparer.Compare(left, right); -#if !NET20 && !NETSTANDARD1_3 +#if !NET20 /// /// Compares two strings according to the Unicode rules for case-insensitive /// identifier comparison (lower-case mapping). diff --git a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.SectionNameMatching.cs b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.SectionNameMatching.cs index 8dfd35910f432..b310f906f72cd 100644 --- a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.SectionNameMatching.cs +++ b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.SectionNameMatching.cs @@ -114,7 +114,7 @@ public bool IsMatch(string s) numberRangePairs.ToImmutableAndFree()); } - internal static bool TryUnescapeSectionName(string sectionName, out string? escapedSectionName) + internal static string UnescapeSectionName(string sectionName) { var sb = new StringBuilder(); SectionNameLexer lexer = new SectionNameLexer(sectionName); @@ -125,9 +125,14 @@ internal static bool TryUnescapeSectionName(string sectionName, out string? esca { sb.Append(lexer.EatCurrentCharacter()); } + else + { + // We only call this on strings that were already passed through IsAbsoluteEditorConfigPath, so + // we shouldn't have any other token kinds here. + throw ExceptionUtilities.UnexpectedValue(tokenKind); + } } - escapedSectionName = sb.ToString(); - return true; + return sb.ToString(); } /// diff --git a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.cs b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.cs index a1c4f920e136e..148d089f0bbb1 100644 --- a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.cs +++ b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.cs @@ -298,7 +298,8 @@ public Section(string name, ImmutableDictionary properties) } /// - /// The name as present directly in the section specification of the editorconfig file. + /// For regular files, the name as present directly in the section specification of the editorconfig file. For sections in + /// global configs, this is the unescaped full file path. /// public string Name { get; } diff --git a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfigSet.cs b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfigSet.cs index db234604c7b39..470800f257c6a 100644 --- a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfigSet.cs +++ b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfigSet.cs @@ -28,6 +28,7 @@ public sealed class AnalyzerConfigSet { /// /// The list of s in this set. This list has been sorted per . + /// This does not include any of the global configs that were merged into . /// private readonly ImmutableArray _analyzerConfigs; @@ -197,13 +198,14 @@ public AnalyzerConfigOptionsResult GetOptionsForSourcePath(string sourcePath) var normalizedPath = PathUtilities.NormalizeWithForwardSlash(sourcePath); normalizedPath = PathUtilities.ExpandAbsolutePathWithRelativeParts(normalizedPath); - // If we have a global config, add any sections that match the full path + // If we have a global config, add any sections that match the full path. We can have at most one section since + // we would have merged them earlier. foreach (var section in _globalConfig.NamedSections) { - var escapedSectionName = TryUnescapeSectionName(section.Name, out var sectionName); - if (escapedSectionName && normalizedPath.Equals(sectionName, Section.NameComparer)) + if (normalizedPath.Equals(section.Name, Section.NameComparer)) { sectionKey.Add(section); + break; } } int globalConfigOptionsCount = sectionKey.Count; @@ -305,7 +307,7 @@ public AnalyzerConfigOptionsResult GetOptionsForSourcePath(string sourcePath) result = new AnalyzerConfigOptionsResult( treeOptionsBuilder.Count > 0 ? treeOptionsBuilder.ToImmutable() : SyntaxTree.EmptyDiagnosticOptions, - analyzerOptionsBuilder.Count > 0 ? analyzerOptionsBuilder.ToImmutable() : AnalyzerConfigOptions.EmptyDictionary, + analyzerOptionsBuilder.Count > 0 ? analyzerOptionsBuilder.ToImmutable() : DictionaryAnalyzerConfigOptions.EmptyDictionary, diagnosticBuilder.ToImmutableAndFree()); if (_optionsCache.TryAdd(sectionKey, result)) @@ -502,7 +504,10 @@ internal void MergeIntoGlobalConfig(AnalyzerConfig config, DiagnosticBag diagnos { if (IsAbsoluteEditorConfigPath(section.Name)) { - MergeSection(config.PathToFile, section, config.GlobalLevel, isGlobalSection: false); + // Let's recreate the section with the name unescaped, since we can then properly merge and match it later + var unescapedSection = new Section(UnescapeSectionName(section.Name), section.Properties); + + MergeSection(config.PathToFile, unescapedSection, config.GlobalLevel, isGlobalSection: false); } else { diff --git a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.SuppressionDiagnostic.cs b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.SuppressionDiagnostic.cs index b4532ac411c4e..043ab09c85132 100644 --- a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.SuppressionDiagnostic.cs +++ b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.SuppressionDiagnostic.cs @@ -85,8 +85,6 @@ public override bool Equals(Diagnostic? obj) Equals(_suppressionJustification, other._suppressionJustification); } - public override bool Equals(object? obj) => obj is Diagnostic diagnostic && Equals(diagnostic); - public override int GetHashCode() { return Hash.Combine(_originalDiagnostic.GetHashCode(), diff --git a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs index 9e61cff4ef2f5..8baa2e86d268d 100644 --- a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs +++ b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs @@ -16,6 +16,7 @@ using System.Threading; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -30,7 +31,8 @@ internal readonly struct BuildPaths internal string ClientDirectory { get; } /// - /// The path in which the compilation takes place. + /// The path in which the compilation takes place. This is also referred to as "baseDirectory" in + /// the code base. /// internal string WorkingDirectory { get; } @@ -84,7 +86,7 @@ internal abstract partial class CommonCompiler /// /// The used to access the file system inside this instance. /// - internal ICommonCompilerFileSystem FileSystem { get; set; } = StandardFileSystem.Instance; + internal ICommonCompilerFileSystem FileSystem { get; set; } private readonly HashSet _reportedDiagnostics = new HashSet(); @@ -117,7 +119,7 @@ protected abstract void ResolveAnalyzersFromArguments( out ImmutableArray analyzers, out ImmutableArray generators); - public CommonCompiler(CommandLineParser parser, string? responseFile, string[] args, BuildPaths buildPaths, string? additionalReferenceDirectories, IAnalyzerAssemblyLoader assemblyLoader, GeneratorDriverCache? driverCache) + public CommonCompiler(CommandLineParser parser, string? responseFile, string[] args, BuildPaths buildPaths, string? additionalReferenceDirectories, IAnalyzerAssemblyLoader assemblyLoader, GeneratorDriverCache? driverCache, ICommonCompilerFileSystem? fileSystem) { IEnumerable allArgs = args; @@ -132,11 +134,7 @@ public CommonCompiler(CommandLineParser parser, string? responseFile, string[] a this.AssemblyLoader = assemblyLoader; this.GeneratorDriverCache = driverCache; this.EmbeddedSourcePaths = GetEmbeddedSourcePaths(Arguments); - - if (Arguments.ParseOptions.Features.ContainsKey("debug-determinism")) - { - EmitDeterminismKey(Arguments, args, buildPaths.WorkingDirectory, parser); - } + this.FileSystem = fileSystem ?? StandardFileSystem.Instance; } internal abstract bool SuppressDefaultResponseFile(IEnumerable args); @@ -933,8 +931,8 @@ private static CompilerAnalyzerConfigOptionsProvider UpdateAnalyzerConfigOptions // Optimization: don't create a bunch of entries pointing to a no-op if (options.Count > 0) { - Debug.Assert(existing.GetOptions(syntaxTree) == CompilerAnalyzerConfigOptions.Empty); - builder.Add(syntaxTree, new CompilerAnalyzerConfigOptions(options)); + Debug.Assert(existing.GetOptions(syntaxTree) == DictionaryAnalyzerConfigOptions.Empty); + builder.Add(syntaxTree, new DictionaryAnalyzerConfigOptions(options)); } i++; } @@ -948,8 +946,8 @@ private static CompilerAnalyzerConfigOptionsProvider UpdateAnalyzerConfigOptions // Optimization: don't create a bunch of entries pointing to a no-op if (options.Count > 0) { - Debug.Assert(existing.GetOptions(additionalFiles[i]) == CompilerAnalyzerConfigOptions.Empty); - builder.Add(additionalFiles[i], new CompilerAnalyzerConfigOptions(options)); + Debug.Assert(existing.GetOptions(additionalFiles[i]) == DictionaryAnalyzerConfigOptions.Empty); + builder.Add(additionalFiles[i], new DictionaryAnalyzerConfigOptions(options)); } } } @@ -995,7 +993,7 @@ private void CompileAndEmit( if (Arguments.AnalyzerConfigPaths.Length > 0) { Debug.Assert(analyzerConfigSet is object); - analyzerConfigProvider = analyzerConfigProvider.WithGlobalOptions(new CompilerAnalyzerConfigOptions(analyzerConfigSet.GetOptionsForSourcePath(string.Empty).AnalyzerOptions)); + analyzerConfigProvider = analyzerConfigProvider.WithGlobalOptions(new DictionaryAnalyzerConfigOptions(analyzerConfigSet.GetOptionsForSourcePath(string.Empty).AnalyzerOptions)); // TODO(https://github.com/dotnet/roslyn/issues/31916): The compiler currently doesn't support // configuring diagnostic reporting on additional text files individually. @@ -1146,6 +1144,11 @@ private void CompileAndEmit( emitOptions = emitOptions.WithPdbFilePath(Path.GetFileName(emitOptions.PdbFilePath)); } + if (Arguments.ParseOptions.Features.ContainsKey("debug-determinism")) + { + EmitDeterminismKey(compilation, FileSystem, additionalTextFiles, analyzers, generators, Arguments.PathMap, emitOptions); + } + if (Arguments.SourceLink != null) { var sourceLinkStreamOpt = OpenFile( @@ -1259,14 +1262,9 @@ private void CompileAndEmit( return; } - success = compilation.GenerateResourcesAndDocumentationComments( - moduleBeingBuilt, - xmlStreamDisposerOpt?.Stream, - win32ResourceStreamOpt, - useRawWin32Resources: false, - emitOptions.OutputNameOverride, - diagnostics, - cancellationToken); + success = + compilation.GenerateResources(moduleBeingBuilt, win32ResourceStreamOpt, useRawWin32Resources: false, diagnostics, cancellationToken) && + compilation.GenerateDocumentationComments(xmlStreamDisposerOpt?.Stream, emitOptions.OutputNameOverride, diagnostics, cancellationToken); } } @@ -1657,68 +1655,20 @@ protected virtual CultureInfo Culture } } - private static void EmitDeterminismKey(CommandLineArguments args, string[] rawArgs, string baseDirectory, CommandLineParser parser) - { - var key = CreateDeterminismKey(args, rawArgs, baseDirectory, parser); - var filePath = Path.Combine(args.OutputDirectory, args.OutputFileName + ".key"); - using (var stream = File.Create(filePath)) - { - var bytes = Encoding.UTF8.GetBytes(key); - stream.Write(bytes, 0, bytes.Length); - } - } - - /// - /// The string returned from this function represents the inputs to the compiler which impact determinism. It is - /// meant to be inline with the specification here: - /// - /// - https://github.com/dotnet/roslyn/blob/main/docs/compilers/Deterministic%20Inputs.md - /// - /// Issue #8193 tracks filling this out to the full specification. - /// - /// https://github.com/dotnet/roslyn/issues/8193 - /// - private static string CreateDeterminismKey(CommandLineArguments args, string[] rawArgs, string baseDirectory, CommandLineParser parser) + private void EmitDeterminismKey( + Compilation compilation, + ICommonCompilerFileSystem fileSystem, + ImmutableArray additionalTexts, + ImmutableArray analyzers, + ImmutableArray generators, + ImmutableArray> pathMap, + EmitOptions? emitOptions) { - List diagnostics = new List(); - var flattenedArgs = ArrayBuilder.GetInstance(); - parser.FlattenArgs(rawArgs, diagnostics, flattenedArgs, null, baseDirectory); - - var builder = new StringBuilder(); - var name = !string.IsNullOrEmpty(args.OutputFileName) - ? Path.GetFileNameWithoutExtension(Path.GetFileName(args.OutputFileName)) - : $"no-output-name-{Guid.NewGuid().ToString()}"; - - builder.AppendLine($"{name}"); - builder.AppendLine($"Command Line:"); - foreach (var current in flattenedArgs) - { - builder.AppendLine($"\t{current}"); - } - - builder.AppendLine("Source Files:"); - var hash = MD5.Create(); - foreach (var sourceFile in args.SourceFiles) - { - var sourceFileName = Path.GetFileName(sourceFile.Path); - - string hashValue; - try - { - var bytes = File.ReadAllBytes(sourceFile.Path); - var hashBytes = hash.ComputeHash(bytes); - var data = BitConverter.ToString(hashBytes); - hashValue = data.Replace("-", ""); - } - catch (Exception ex) - { - hashValue = $"Could not compute {ex.Message}"; - } - builder.AppendLine($"\t{sourceFileName} - {hashValue}"); - } - - flattenedArgs.Free(); - return builder.ToString(); + var key = compilation.GetDeterministicKey(additionalTexts, analyzers, generators, pathMap, emitOptions); + var filePath = Path.Combine(Arguments.OutputDirectory, Arguments.OutputFileName + ".key"); + using var stream = fileSystem.OpenFile(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None); + var bytes = Encoding.UTF8.GetBytes(key); + stream.Write(bytes, 0, bytes.Length); } } } diff --git a/src/Compilers/Core/Portable/CommandLine/SarifDiagnosticComparer.cs b/src/Compilers/Core/Portable/CommandLine/SarifDiagnosticComparer.cs index 8ff63a502d434..7771d6804ae01 100644 --- a/src/Compilers/Core/Portable/CommandLine/SarifDiagnosticComparer.cs +++ b/src/Compilers/Core/Portable/CommandLine/SarifDiagnosticComparer.cs @@ -46,18 +46,14 @@ public bool Equals(DiagnosticDescriptor? x, DiagnosticDescriptor? y) return false; } - // The properties are guaranteed to be non-null by DiagnosticDescriptor invariants. - Debug.Assert(x.Description != null && x.Title != null && x.CustomTags != null); - Debug.Assert(y.Description != null && y.Title != null && y.CustomTags != null); - - return (x.Category == y.Category + return x.Category == y.Category && x.DefaultSeverity == y.DefaultSeverity - && x.Description!.Equals(y.Description) + && x.Description.Equals(y.Description) && x.HelpLinkUri == y.HelpLinkUri && x.Id == y.Id && x.IsEnabledByDefault == y.IsEnabledByDefault - && x.Title!.Equals(y.Title) - && x.ImmutableCustomTags.SequenceEqual(y.ImmutableCustomTags)); + && x.Title.Equals(y.Title) + && x.ImmutableCustomTags.SequenceEqual(y.ImmutableCustomTags); } public int GetHashCode(DiagnosticDescriptor obj) @@ -67,17 +63,13 @@ public int GetHashCode(DiagnosticDescriptor obj) return 0; } - // The properties are guaranteed to be non-null by DiagnosticDescriptor invariants. - Debug.Assert(obj.Category != null && obj.Description != null && obj.HelpLinkUri != null - && obj.Id != null && obj.Title != null && obj.CustomTags != null); - - return Hash.Combine(obj.Category!.GetHashCode(), + return Hash.Combine(obj.Category.GetHashCode(), Hash.Combine(obj.DefaultSeverity.GetHashCode(), - Hash.Combine(obj.Description!.GetHashCode(), - Hash.Combine(obj.HelpLinkUri!.GetHashCode(), - Hash.Combine(obj.Id!.GetHashCode(), + Hash.Combine(obj.Description.GetHashCode(), + Hash.Combine(obj.HelpLinkUri.GetHashCode(), + Hash.Combine(obj.Id.GetHashCode(), Hash.Combine(obj.IsEnabledByDefault.GetHashCode(), - Hash.Combine(obj.Title!.GetHashCode(), + Hash.Combine(obj.Title.GetHashCode(), Hash.CombineValues(obj.ImmutableCustomTags)))))))); } } diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index d48762238a837..c19334290734e 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -123,6 +123,101 @@ protected static IReadOnlyDictionary SyntaxTreeCommonFeatures(IE internal abstract void SerializePdbEmbeddedCompilationOptions(BlobBuilder builder); + /// + /// This method generates a string that represents the input content to the compiler which impacts + /// the output of the build. This string is effectively a content key for a + /// with these values that can be used to identify the outputs. + /// + /// The returned string has the following properties: + /// + /// + /// + /// + /// The format is undefined. Consumers should assume the format and content can change between + /// compiler versions. + /// + /// + /// + /// + /// It is designed to be human readable and diffable. This is to help developers + /// understand the difference between two compilations which is impacting the deterministic + /// output + /// + /// + /// + /// + /// It is *not* in a minimal form. If used as a key in say a content addressable storage consumers + /// should first pass it through a strong hashing function. + /// + /// + /// + /// + /// Compilations which do not use the /deterministic option can still use this API but + /// the results will change on every invocation. + /// + /// + /// The set of inputs that impact deterministic output are described in the following document + /// - https://github.com/dotnet/roslyn/blob/main/docs/compilers/Deterministic%20Inputs.md + /// + /// There are a few dark corners of determinism that are not captured with this key as they are + /// considered outside the scope of this work: + /// + /// + /// + /// + /// Environment variables: clever developers can subvert determinism by manipulation of + /// environment variables that impact program execution. For example changing normal library + /// loading by manipulating the %LIBPATH% environment variable. Doing so can cause a change + /// in deterministic output of compilation by changing compiler, runtime or generator + /// dependencies. + /// + /// + /// + /// + /// Manipulation of strong name keys: strong name keys are read "on demand" by the compiler + /// and both normal compilation and this key can have non-determinstic output if they are + /// manipulated at the correct point in program execution. That is an existing limitation + /// of compilation that is tracked by https://github.com/dotnet/roslyn/issues/57940 + /// + /// + /// + /// This API can throw exceptions in a few cases like invalid file paths. + /// + internal static string GetDeterministicKey( + CompilationOptions compilationOptions, + ImmutableArray syntaxTrees, + ImmutableArray references, + ImmutableArray publicKey, + ImmutableArray additionalTexts = default, + ImmutableArray analyzers = default, + ImmutableArray generators = default, + ImmutableArray> pathMap = default, + EmitOptions? emitOptions = null, + DeterministicKeyOptions options = DeterministicKeyOptions.Default) + { + return DeterministicKey.GetDeterministicKey( + compilationOptions, syntaxTrees, references, publicKey, additionalTexts, analyzers, generators, pathMap, emitOptions, options); + } + + internal string GetDeterministicKey( + ImmutableArray additionalTexts = default, + ImmutableArray analyzers = default, + ImmutableArray generators = default, + ImmutableArray> pathMap = default, + EmitOptions? emitOptions = null, + DeterministicKeyOptions options = DeterministicKeyOptions.Default) + => GetDeterministicKey( + Options, + CommonSyntaxTrees, + ExternalReferences.Concat(DirectiveReferences), + Assembly.Identity.PublicKey, + additionalTexts, + analyzers, + generators, + pathMap, + emitOptions, + options); + internal static void ValidateScriptCompilationParameters(Compilation? previousScriptCompilation, Type? returnType, ref Type? globalsType) { if (globalsType != null && !IsValidHostObjectType(globalsType)) @@ -1063,6 +1158,10 @@ public INamedTypeSymbol CreateNativeIntegerTypeSymbol(bool signed) /// a match is found in one module in an assembly, no further modules within that assembly are searched. /// /// Type forwarders are ignored, and not considered part of the assembly where the TypeForwardAttribute is written. + /// + /// Ambiguities are detected on each nested level. For example, if A+B is requested, and there are multiple As but only one of them has a B nested + /// type, the lookup will be considered ambiguous and null will be returned. + /// /// public INamedTypeSymbol? GetTypeByMetadataName(string fullyQualifiedMetadataName) { @@ -2330,14 +2429,22 @@ internal bool CreateDebugDocuments(DebugDocumentsBuilder documentsBuilder, IEnum internal abstract void AddDebugSourceDocumentsForChecksumDirectives(DebugDocumentsBuilder documentsBuilder, SyntaxTree tree, DiagnosticBag diagnostics); /// - /// Update resources and generate XML documentation comments. + /// Update resources. /// /// True if successful. - internal abstract bool GenerateResourcesAndDocumentationComments( - CommonPEModuleBuilder moduleBeingBuilt, - Stream? xmlDocumentationStream, - Stream? win32ResourcesStream, + internal abstract bool GenerateResources( + CommonPEModuleBuilder moduleBuilder, + Stream? win32Resources, bool useRawWin32Resources, + DiagnosticBag diagnostics, + CancellationToken cancellationToken); + + /// + /// Generate XML documentation comments. + /// + /// True if successful. + internal abstract bool GenerateDocumentationComments( + Stream? xmlDocStream, string? outputNameOverride, DiagnosticBag diagnostics, CancellationToken cancellationToken); @@ -2738,14 +2845,8 @@ internal EmitResult Emit( { // NOTE: We generate documentation even in presence of compile errors. // https://github.com/dotnet/roslyn/issues/37996 tracks revisiting this behavior. - if (!GenerateResourcesAndDocumentationComments( - moduleBeingBuilt, - xmlDocumentationStream, - win32Resources, - useRawWin32Resources: rebuildData is object, - options.OutputNameOverride, - diagnostics, - cancellationToken)) + if (!GenerateResources(moduleBeingBuilt, win32Resources, useRawWin32Resources: rebuildData is object, diagnostics, cancellationToken) || + !GenerateDocumentationComments(xmlDocumentationStream, options.OutputNameOverride, diagnostics, cancellationToken)) { success = false; } @@ -2755,6 +2856,12 @@ internal EmitResult Emit( ReportUnusedImports(diagnostics, cancellationToken); } } + else if (xmlDocumentationStream != null) + { + // If we're in metadata only, and the caller asks for xml docs, then still proceed and generate those. + success = GenerateDocumentationComments( + xmlDocumentationStream, options.OutputNameOverride, diagnostics, cancellationToken); + } } finally { diff --git a/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs b/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs index 81ce6f3109049..117354e214d75 100644 --- a/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs +++ b/src/Compilers/Core/Portable/Compilation/CompilationOptions.cs @@ -552,6 +552,8 @@ public CompilationOptions WithOverflowChecks(bool checkOverflow) [Obsolete] protected abstract CompilationOptions CommonWithFeatures(ImmutableArray features); + internal abstract DeterministicKeyBuilder CreateDeterministicKeyBuilder(); + /// /// Performs validation of options compatibilities and generates diagnostics if needed /// diff --git a/src/Compilers/Core/Portable/Compilation/DeterministicKey.cs b/src/Compilers/Core/Portable/Compilation/DeterministicKey.cs new file mode 100644 index 0000000000000..199c18f5c65cb --- /dev/null +++ b/src/Compilers/Core/Portable/Compilation/DeterministicKey.cs @@ -0,0 +1,105 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis +{ + internal abstract class SyntaxTreeKey + { + public abstract string FilePath { get; } + public abstract ParseOptions Options { get; } + + protected SyntaxTreeKey() + { + } + + public abstract SourceText GetText(CancellationToken cancellationToken = default); + + public static SyntaxTreeKey Create(SyntaxTree tree) + => new DefaultSyntaxTreeKey(tree); + + private sealed class DefaultSyntaxTreeKey : SyntaxTreeKey + { + private readonly SyntaxTree _tree; + + public DefaultSyntaxTreeKey(SyntaxTree tree) + { + _tree = tree; + } + + public override string FilePath + => _tree.FilePath; + + public override ParseOptions Options + => _tree.Options; + + public override SourceText GetText(CancellationToken cancellationToken = default) + => _tree.GetText(cancellationToken); + } + } + + internal static class DeterministicKey + { + public static string GetDeterministicKey( + CompilationOptions compilationOptions, + ImmutableArray syntaxTrees, + ImmutableArray references, + ImmutableArray publicKey = default, + ImmutableArray additionalTexts = default, + ImmutableArray analyzers = default, + ImmutableArray generators = default, + ImmutableArray> pathMap = default, + EmitOptions? emitOptions = null, + DeterministicKeyOptions options = DeterministicKeyOptions.Default, + CancellationToken cancellationToken = default) + { + return GetDeterministicKey( + compilationOptions, + syntaxTrees.SelectAsArray(static t => SyntaxTreeKey.Create(t)), + references, + publicKey, + additionalTexts, + analyzers, + generators, + pathMap, + emitOptions, + options, + cancellationToken); + } + + public static string GetDeterministicKey( + CompilationOptions compilationOptions, + ImmutableArray syntaxTrees, + ImmutableArray references, + ImmutableArray publicKey, + ImmutableArray additionalTexts = default, + ImmutableArray analyzers = default, + ImmutableArray generators = default, + ImmutableArray> pathMap = default, + EmitOptions? emitOptions = null, + DeterministicKeyOptions options = DeterministicKeyOptions.Default, + CancellationToken cancellationToken = default) + { + var keyBuilder = compilationOptions.CreateDeterministicKeyBuilder(); + return keyBuilder.GetKey( + compilationOptions, + syntaxTrees, + references, + publicKey, + additionalTexts.NullToEmpty(), + analyzers.NullToEmpty(), + generators.NullToEmpty(), + pathMap.NullToEmpty(), + emitOptions, + options, + cancellationToken); + } + } +} diff --git a/src/Compilers/Core/Portable/Compilation/DeterministicKeyBuilder.cs b/src/Compilers/Core/Portable/Compilation/DeterministicKeyBuilder.cs new file mode 100644 index 0000000000000..be92b6a27b567 --- /dev/null +++ b/src/Compilers/Core/Portable/Compilation/DeterministicKeyBuilder.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis +{ + /// + /// The string returned from this function represents the inputs to the compiler which impact determinism. It is + /// meant to be inline with the specification here: + /// + /// - https://github.com/dotnet/roslyn/blob/main/docs/compilers/Deterministic%20Inputs.md + /// + /// Options which can cause compilation failure, but doesn't impact the result of a successful + /// compilation should be included. That is because it is interesting to describe error states + /// not just success states. Think about caching build failures as well as build successes. + /// + /// When an option is omitted, say if there is no value for a public crypto key, we should emit + /// the property with a null value vs. omitting the property. Either approach would produce + /// correct results the preference is to be declarative that an option is omitted. + /// + internal abstract class DeterministicKeyBuilder + { + protected DeterministicKeyBuilder() + { + } + + protected void WriteFilePath( + JsonWriter writer, + string propertyName, + string? filePath, + ImmutableArray> pathMap, + DeterministicKeyOptions options) + { + if ((options & DeterministicKeyOptions.IgnorePaths) != 0) + { + filePath = Path.GetFileName(filePath); + } + else if (filePath is not null) + { + filePath = PathUtilities.NormalizePathPrefix(filePath, pathMap); + } + + writer.Write(propertyName, filePath); + } + + internal static string EncodeByteArrayValue(ReadOnlySpan value) + { + var builder = PooledStringBuilder.GetInstance(); + EncodeByteArrayValue(value, builder.Builder); + return builder.ToStringAndFree(); + } + + internal static void EncodeByteArrayValue(ReadOnlySpan value, StringBuilder builder) + { + foreach (var b in value) + { + builder.Append(b.ToString("x")); + } + } + + protected static void WriteByteArrayValue(JsonWriter writer, string name, ReadOnlySpan value) => + writer.Write(name, EncodeByteArrayValue(value)); + + protected static void WriteVersion(JsonWriter writer, string key, Version version) + { + writer.WriteKey(key); + writer.WriteObjectStart(); + writer.Write("major", version.Major); + writer.Write("minor", version.Minor); + writer.Write("build", version.Build); + writer.Write("revision", version.Revision); + writer.WriteObjectEnd(); + } + + protected void WriteType(JsonWriter writer, string key, Type? type) + { + writer.WriteKey(key); + WriteType(writer, type); + } + + protected void WriteType(JsonWriter writer, Type? type) + { + if (type is null) + { + writer.WriteNull(); + return; + } + + writer.WriteObjectStart(); + writer.Write("fullName", type.FullName); + // Note that the file path to the assembly is deliberately not included here. The file path + // of the assembly does not contribute to the output of the program. + writer.Write("assemblyName", type.Assembly.FullName); + writer.Write("mvid", GetGuidValue(type.Assembly.ManifestModule.ModuleVersionId)); + writer.WriteObjectEnd(); + } + + private (JsonWriter, PooledStringBuilder) CreateWriter() + { + var builder = PooledStringBuilder.GetInstance(); + var writer = new StringWriter(builder); + return (new JsonWriter(writer), builder); + } + + internal string GetKey( + CompilationOptions compilationOptions, + ImmutableArray syntaxTrees, + ImmutableArray references, + ImmutableArray publicKey, + ImmutableArray additionalTexts, + ImmutableArray analyzers, + ImmutableArray generators, + ImmutableArray> pathMap, + EmitOptions? emitOptions, + DeterministicKeyOptions options, + CancellationToken cancellationToken) + { + additionalTexts = additionalTexts.NullToEmpty(); + analyzers = analyzers.NullToEmpty(); + generators = generators.NullToEmpty(); + + var (writer, builder) = CreateWriter(); + + writer.WriteObjectStart(); + + writer.WriteKey("compilation"); + WriteCompilation(writer, compilationOptions, syntaxTrees, references, publicKey, pathMap, options, cancellationToken); + writer.WriteKey("additionalTexts"); + writeAdditionalTexts(); + writer.WriteKey("analyzers"); + writeAnalyzers(); + writer.WriteKey("generators"); + writeGenerators(); + writer.WriteKey("emitOptions"); + WriteEmitOptions(writer, emitOptions, pathMap, options); + + writer.WriteObjectEnd(); + + return builder.ToStringAndFree(); + + void writeAdditionalTexts() + { + writer.WriteArrayStart(); + foreach (var additionalText in additionalTexts) + { + cancellationToken.ThrowIfCancellationRequested(); + + writer.WriteObjectStart(); + WriteFilePath(writer, "fileName", additionalText.Path, pathMap, options); + writer.WriteKey("text"); + WriteSourceText(writer, additionalText.GetText(cancellationToken)); + writer.WriteObjectEnd(); + } + writer.WriteArrayEnd(); + } + + void writeAnalyzers() + { + writer.WriteArrayStart(); + foreach (var analyzer in analyzers) + { + cancellationToken.ThrowIfCancellationRequested(); + WriteType(writer, analyzer.GetType()); + } + writer.WriteArrayEnd(); + } + + void writeGenerators() + { + writer.WriteArrayStart(); + foreach (var generator in generators) + { + cancellationToken.ThrowIfCancellationRequested(); + WriteType(writer, generator.GetType()); + } + writer.WriteArrayEnd(); + } + } + + internal static string GetGuidValue(in Guid guid) => guid.ToString("D"); + + private void WriteCompilation( + JsonWriter writer, + CompilationOptions compilationOptions, + ImmutableArray syntaxTrees, + ImmutableArray references, + ImmutableArray publicKey, + ImmutableArray> pathMap, + DeterministicKeyOptions options, + CancellationToken cancellationToken) + { + writer.WriteObjectStart(); + writeToolsVersions(); + + WriteByteArrayValue(writer, "publicKey", publicKey.AsSpan()); + writer.WriteKey("options"); + WriteCompilationOptions(writer, compilationOptions); + + writer.WriteKey("syntaxTrees"); + writer.WriteArrayStart(); + foreach (var syntaxTree in syntaxTrees) + { + cancellationToken.ThrowIfCancellationRequested(); + WriteSyntaxTree(writer, syntaxTree, pathMap, options, cancellationToken); + } + writer.WriteArrayEnd(); + + writer.WriteKey("references"); + writer.WriteArrayStart(); + foreach (var reference in references) + { + cancellationToken.ThrowIfCancellationRequested(); + WriteMetadataReference(writer, reference, pathMap, options, cancellationToken); + } + writer.WriteArrayEnd(); + writer.WriteObjectEnd(); + + void writeToolsVersions() + { + writer.WriteKey("toolsVersions"); + writer.WriteObjectStart(); + if ((options & DeterministicKeyOptions.IgnoreToolVersions) == 0) + { + var compilerVersion = typeof(Compilation).Assembly.GetCustomAttribute()?.InformationalVersion; + writer.Write("compilerVersion", compilerVersion); + + var runtimeVersion = typeof(object).Assembly.GetCustomAttribute()?.InformationalVersion; + writer.Write("runtimeVersion", runtimeVersion); + + writer.Write("frameworkDescription", RuntimeInformation.FrameworkDescription); + writer.Write("osDescription", RuntimeInformation.OSDescription); + } + + writer.WriteObjectEnd(); + } + } + + private void WriteSyntaxTree( + JsonWriter writer, + SyntaxTreeKey syntaxTree, + ImmutableArray> pathMap, + DeterministicKeyOptions options, + CancellationToken cancellationToken) + { + writer.WriteObjectStart(); + WriteFilePath(writer, "fileName", syntaxTree.FilePath, pathMap, options); + writer.WriteKey("text"); + WriteSourceText(writer, syntaxTree.GetText(cancellationToken)); + writer.WriteKey("parseOptions"); + WriteParseOptions(writer, syntaxTree.Options); + writer.WriteObjectEnd(); + } + + private void WriteSourceText(JsonWriter writer, SourceText? sourceText) + { + if (sourceText is null) + { + writer.WriteNull(); + return; + } + + writer.WriteObjectStart(); + WriteByteArrayValue(writer, "checksum", sourceText.GetChecksum().AsSpan()); + writer.Write("checksumAlgorithm", sourceText.ChecksumAlgorithm); + writer.Write("encodingName", sourceText.Encoding?.EncodingName); + writer.WriteObjectEnd(); + } + + internal void WriteMetadataReference( + JsonWriter writer, + MetadataReference reference, + ImmutableArray> pathMap, + DeterministicKeyOptions deterministicKeyOptions, + CancellationToken cancellationToken) + { + writer.WriteObjectStart(); + if (reference is PortableExecutableReference peReference) + { + switch (peReference.GetMetadata()) + { + case AssemblyMetadata assemblyMetadata: + { + var modules = assemblyMetadata.GetModules(); + writeModuleMetadata(modules[0]); + writer.WriteKey("secondaryModules"); + writer.WriteArrayStart(); + for (var i = 1; i < modules.Length; i++) + { + writer.WriteObjectStart(); + writeModuleMetadata(modules[i]); + writer.WriteObjectEnd(); + } + writer.WriteArrayEnd(); + } + break; + case ModuleMetadata m: + writeModuleMetadata(m); + break; + case var m: + throw ExceptionUtilities.UnexpectedValue(m); + } + + writer.WriteKey("properties"); + writeMetadataReferenceProperties(writer, reference.Properties); + + } + else if (reference is CompilationReference compilationReference) + { + writer.WriteKey("compilation"); + var compilation = compilationReference.Compilation; + var builder = compilation.Options.CreateDeterministicKeyBuilder(); + builder.WriteCompilation( + writer, + compilation.Options, + compilation.SyntaxTrees.SelectAsArray(static x => SyntaxTreeKey.Create(x)), + compilation.References.AsImmutable(), + compilation.Assembly.Identity.PublicKey, + pathMap, + deterministicKeyOptions, + cancellationToken); + } + else + { + throw ExceptionUtilities.UnexpectedValue(reference); + } + + writer.WriteObjectEnd(); + + void writeModuleMetadata(ModuleMetadata moduleMetadata) + { + // The path of a reference, unlike the path of a file, does not contribute to the output + // of the compilation. Only the MVID, name and version contribute here hence the file path + // is deliberately omitted here. + var peReader = moduleMetadata.GetMetadataReader(); + if (peReader.IsAssembly) + { + var assemblyDef = peReader.GetAssemblyDefinition(); + writer.Write("name", peReader.GetString(assemblyDef.Name)); + WriteVersion(writer, "version", assemblyDef.Version); + WriteByteArrayValue(writer, "publicKey", peReader.GetBlobBytes(assemblyDef.PublicKey).AsSpan()); + } + else + { + var moduleDef = peReader.GetModuleDefinition(); + writer.Write("name", peReader.GetString(moduleDef.Name)); + } + + writer.Write("mvid", GetGuidValue(moduleMetadata.GetModuleVersionId())); + } + + static void writeMetadataReferenceProperties(JsonWriter writer, MetadataReferenceProperties properties) + { + writer.WriteObjectStart(); + writer.Write("kind", properties.Kind); + writer.Write("embedInteropTypes", properties.EmbedInteropTypes); + writer.WriteKey("aliases"); + writer.WriteArrayStart(); + foreach (var alias in properties.Aliases) + { + writer.Write(alias); + } + writer.WriteArrayEnd(); + writer.WriteObjectEnd(); + } + } + + private void WriteEmitOptions( + JsonWriter writer, + EmitOptions? options, + ImmutableArray> pathMap, + DeterministicKeyOptions deterministicKeyOptions) + { + if (options is null) + { + writer.WriteNull(); + return; + } + + writer.WriteObjectStart(); + writer.Write("emitMetadataOnly", options.EmitMetadataOnly); + writer.Write("tolerateErrors", options.TolerateErrors); + writer.Write("includePrivateMembers", options.IncludePrivateMembers); + writer.WriteKey("instrumentationKinds"); + writer.WriteArrayStart(); + if (!options.InstrumentationKinds.IsDefault) + { + foreach (var kind in options.InstrumentationKinds) + { + writer.Write(kind); + } + } + writer.WriteArrayEnd(); + + writeSubsystemVersion(writer, options.SubsystemVersion); + writer.Write("fileAlignment", options.FileAlignment); + writer.Write("highEntropyVirtualAddressSpace", options.HighEntropyVirtualAddressSpace); + writer.WriteInvariant("baseAddress", options.BaseAddress); + writer.Write("debugInformationFormat", options.DebugInformationFormat); + writer.Write("outputNameOverride", options.OutputNameOverride); + WriteFilePath(writer, "pdbFilePath", options.PdbFilePath, pathMap, deterministicKeyOptions); + writer.Write("pdbChecksumAlgorithm", options.PdbChecksumAlgorithm.Name); + writer.Write("runtimeMetadataVersion", options.RuntimeMetadataVersion); + writer.Write("defaultSourceFileEncoding", options.DefaultSourceFileEncoding?.CodePage); + writer.Write("fallbackSourceFileEncoding", options.FallbackSourceFileEncoding?.CodePage); + writer.WriteObjectEnd(); + + static void writeSubsystemVersion(JsonWriter writer, SubsystemVersion version) + { + writer.WriteKey("subsystemVersion"); + writer.WriteObjectStart(); + writer.Write("major", version.Major); + writer.Write("minor", version.Minor); + writer.WriteObjectEnd(); + } + } + + private void WriteCompilationOptions(JsonWriter writer, CompilationOptions options) + { + writer.WriteObjectStart(); + WriteCompilationOptionsCore(writer, options); + writer.WriteObjectEnd(); + } + + protected virtual void WriteCompilationOptionsCore(JsonWriter writer, CompilationOptions options) + { + // CompilationOption values + writer.Write("outputKind", options.OutputKind); + writer.Write("moduleName", options.ModuleName); + writer.Write("scriptClassName", options.ScriptClassName); + writer.Write("mainTypeName", options.MainTypeName); + WriteByteArrayValue(writer, "cryptoPublicKey", options.CryptoPublicKey.AsSpan()); + writer.Write("cryptoKeyFile", options.CryptoKeyFile); + writer.Write("delaySign", options.DelaySign); + writer.Write("publicSign", options.PublicSign); + writer.Write("checkOverflow", options.CheckOverflow); + writer.Write("platform", options.Platform); + writer.Write("optimizationLevel", options.OptimizationLevel); + writer.Write("generalDiagnosticOption", options.GeneralDiagnosticOption); + writer.Write("warningLevel", options.WarningLevel); + writer.Write("deterministic", options.Deterministic); + writer.Write("debugPlusMode", options.DebugPlusMode); + writer.Write("referencesSupersedeLowerVersions", options.ReferencesSupersedeLowerVersions); + writer.Write("reportSuppressedDiagnostics", options.ReportSuppressedDiagnostics); + writer.Write("nullableContextOptions", options.NullableContextOptions); + + writer.WriteKey("specificDiagnosticOptions"); + writer.WriteArrayStart(); + foreach (var key in options.SpecificDiagnosticOptions.Keys.OrderBy(StringComparer.Ordinal)) + { + writer.WriteObjectStart(); + writer.Write(key, options.SpecificDiagnosticOptions[key]); + writer.WriteObjectEnd(); + } + writer.WriteArrayEnd(); + + if (options.Deterministic) + { + writer.Write("deterministic", true); + writer.WriteNull("localtime"); + } + else + { + writer.Write("deterministic", false); + writer.WriteInvariant("localtime", options.CurrentLocalTime); + + // When using /deterministic- the compiler will *always* emit different binaries hence the + // key we generate here also must be different. We cannot depend on the `localtime` property + // to provide this as the same compilation can occur on different machines at the same + // time. Force the issue here. + writer.Write("nondeterministicMvid", GetGuidValue(Guid.NewGuid())); + } + + // Values which do not impact build success / failure + // - ConcurrentBuild + // - MetadataImportOptions: + // - Options.Features: deprecated + // + + // Not really options but they can impact compilation so we record the types. For the majority + // of compilations this is roughly the equivalent of recording the compiler version but it + // could differ when customers host the compiler via the API. + writer.WriteKey("extensions"); + writer.WriteObjectStart(); + + WriteType(writer, "syntaxTreeOptionsProvider", options.SyntaxTreeOptionsProvider?.GetType()); + WriteType(writer, "metadataReferenceResolver", options.MetadataReferenceResolver?.GetType()); + WriteType(writer, "xmlReferenceResolver", options.XmlReferenceResolver?.GetType()); + WriteType(writer, "sourceReferenceResolver", options.SourceReferenceResolver?.GetType()); + WriteType(writer, "strongNameProvider", options.StrongNameProvider?.GetType()); + WriteType(writer, "assemblyIdentityComparer", options.AssemblyIdentityComparer?.GetType()); + writer.WriteObjectEnd(); + } + + protected void WriteParseOptions(JsonWriter writer, ParseOptions parseOptions) + { + writer.WriteObjectStart(); + WriteParseOptionsCore(writer, parseOptions); + writer.WriteObjectEnd(); + } + + protected virtual void WriteParseOptionsCore(JsonWriter writer, ParseOptions parseOptions) + { + writer.Write("kind", parseOptions.Kind); + writer.Write("specifiedKind", parseOptions.SpecifiedKind); + writer.Write("documentationMode", parseOptions.DocumentationMode); + writer.Write("language", parseOptions.Language); + + writer.WriteKey("features"); + var features = parseOptions.Features; + writer.WriteObjectStart(); + foreach (var key in features.Keys.OrderBy(StringComparer.Ordinal)) + { + writer.Write(key, features[key]); + } + writer.WriteObjectEnd(); + + // Skipped values + // - Errors: not sure if we need that in the key file or not + // - PreprocessorSymbolNames: handled at the language specific level + } + } +} diff --git a/src/Compilers/Core/Portable/Compilation/DeterministicKeyOptions.cs b/src/Compilers/Core/Portable/Compilation/DeterministicKeyOptions.cs new file mode 100644 index 0000000000000..45adb51d997ac --- /dev/null +++ b/src/Compilers/Core/Portable/Compilation/DeterministicKeyOptions.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.CodeAnalysis +{ + [Flags] + internal enum DeterministicKeyOptions + { + /// + /// The default is to include all inputs to the compilation which impact the output of the + /// compilation: binaries or diagnostics. + /// + Default = 0b0, + + /// + /// Ignore all file paths, but still include file names, in the deterministic key. + /// + /// + /// This is useful for scenarios where the consumer is interested in the content of the + /// being the same but aren't concerned precisely with the file + /// path of the content. A typical example of this type of consumer is one that operates + /// in CI where the path changes frequently. + /// + IgnorePaths = 0b0001, + + /// + /// Ignore the versions of the tools contributing to the build (compiler and runtime) + /// + /// + /// Compiler output is not guaranteed to be deterministically equivalent between versions + /// but very often is for wide ranges of versions. This option is useful for consumers + /// who are comfortable ignoring the versions when looking at compiler output. + /// + IgnoreToolVersions = 0b0010, + } +} diff --git a/src/Compilers/Core/Portable/Compilation/SemanticModel.cs b/src/Compilers/Core/Portable/Compilation/SemanticModel.cs index b5363bf7d9b00..61204b54280c5 100644 --- a/src/Compilers/Core/Portable/Compilation/SemanticModel.cs +++ b/src/Compilers/Core/Portable/Compilation/SemanticModel.cs @@ -75,19 +75,7 @@ public SyntaxTree SyntaxTree /// public IOperation? GetOperation(SyntaxNode node, CancellationToken cancellationToken = default(CancellationToken)) { - try - { - return GetOperationCore(node, cancellationToken); - } -#pragma warning disable CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete; tracked by https://github.com/dotnet/roslyn/issues/58375 - catch (Exception e) when (FatalError.ReportIfNonFatalAndCatchUnlessCanceled(e, cancellationToken)) -#pragma warning restore CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete - { - // Log a Non-fatal-watson and then ignore the crash in the attempt of getting operation - Debug.Assert(false, "\n" + e.ToString()); - } - - return null; + return GetOperationCore(node, cancellationToken); } protected abstract IOperation? GetOperationCore(SyntaxNode node, CancellationToken cancellationToken); @@ -875,8 +863,24 @@ public PreprocessingSymbolInfo GetPreprocessingSymbolInfo(SyntaxNode nameSyntax) /// internal abstract void ComputeDeclarationsInNode(SyntaxNode node, ISymbol associatedSymbol, bool getSymbol, ArrayBuilder builder, CancellationToken cancellationToken, int? levelsToCompute = null); + /// + /// Gets a filter that determines whether or not a given syntax node and its descendants should be analyzed for the given + /// declared node and declared symbol. We have scenarios where certain syntax nodes declare multiple symbols, + /// for example record declarations, and we want to avoid duplicate syntax node callbacks for such nodes. + /// Note that the predicate returned by this method filters out both the node and all its descendants from analysis. + /// If you wish to skip analysis just for a specific node, but not its descendants, then add the required logic in + /// . + /// internal virtual Func? GetSyntaxNodesToAnalyzeFilter(SyntaxNode declaredNode, ISymbol declaredSymbol) => null; + /// + /// Determines if the given syntax node with the given containing symbol should be analyzed or not. + /// Note that only the given syntax node will be filtered out from analysis, this API will be invoked separately + /// for each of its descendants. If you wish to skip analysis of the node and all its descendants, then add the required + /// logic to . + /// + internal virtual bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol) => false; + /// /// Takes a Symbol and syntax for one of its declaring syntax reference and returns the topmost syntax node to be used by syntax analyzer. /// diff --git a/src/Compilers/Core/Portable/Compilation/SubsystemVersion.cs b/src/Compilers/Core/Portable/Compilation/SubsystemVersion.cs index 085f027a7ac34..ecceb3d936675 100644 --- a/src/Compilers/Core/Portable/Compilation/SubsystemVersion.cs +++ b/src/Compilers/Core/Portable/Compilation/SubsystemVersion.cs @@ -25,7 +25,7 @@ namespace Microsoft.CodeAnalysis /// - Windows 7 6.01 /// - Windows 8 Release Preview 6.02 /// - public struct SubsystemVersion : IEquatable + public readonly struct SubsystemVersion : IEquatable { /// /// Major subsystem version diff --git a/src/Compilers/Core/Portable/Diagnostic/Diagnostic.DiagnosticWithProgrammaticSuppression.cs b/src/Compilers/Core/Portable/Diagnostic/Diagnostic.DiagnosticWithProgrammaticSuppression.cs index 97967788cd8b4..8afc99283a1da 100644 --- a/src/Compilers/Core/Portable/Diagnostic/Diagnostic.DiagnosticWithProgrammaticSuppression.cs +++ b/src/Compilers/Core/Portable/Diagnostic/Diagnostic.DiagnosticWithProgrammaticSuppression.cs @@ -100,11 +100,6 @@ public override bool Equals(Diagnostic? obj) Equals(_programmaticSuppressionInfo, other._programmaticSuppressionInfo); } - public override bool Equals(object? obj) - { - return this.Equals(obj as Diagnostic); - } - public override int GetHashCode() { return Hash.Combine(_originalUnsuppressedDiagnostic.GetHashCode(), _programmaticSuppressionInfo.GetHashCode()); diff --git a/src/Compilers/Core/Portable/Diagnostic/Diagnostic.cs b/src/Compilers/Core/Portable/Diagnostic/Diagnostic.cs index 8fb0543c2c33d..11cbc9932be10 100644 --- a/src/Compilers/Core/Portable/Diagnostic/Diagnostic.cs +++ b/src/Compilers/Core/Portable/Diagnostic/Diagnostic.cs @@ -171,7 +171,7 @@ public static Diagnostic Create( /// The diagnostic's effective severity. /// The diagnostic's default severity. /// True if the diagnostic is enabled by default - /// The warning level, between 1 and 4 if severity is ; otherwise 0. + /// The warning level, greater than 0 if severity is ; otherwise 0. /// An optional short localizable title describing the diagnostic. /// An optional longer localizable description for the diagnostic. /// An optional hyperlink that provides more detailed information regarding the diagnostic. @@ -220,7 +220,7 @@ public static Diagnostic Create( /// The diagnostic's effective severity. /// The diagnostic's default severity. /// True if the diagnostic is enabled by default - /// The warning level, between 1 and 4 if severity is ; otherwise 0. + /// The warning level, greater than 0 if severity is ; otherwise 0. /// Flag indicating whether the diagnostic is suppressed by a source suppression. /// An optional short localizable title describing the diagnostic. /// An optional longer localizable description for the diagnostic. @@ -418,7 +418,8 @@ public override string ToString() return DiagnosticFormatter.Instance.Format(this, CultureInfo.CurrentUICulture); } - public abstract override bool Equals(object? obj); + public sealed override bool Equals(object? obj) + => obj is Diagnostic diagnostic && Equals(diagnostic); public abstract override int GetHashCode(); diff --git a/src/Compilers/Core/Portable/Diagnostic/DiagnosticWithInfo.cs b/src/Compilers/Core/Portable/Diagnostic/DiagnosticWithInfo.cs index 0c074b58c762b..f7de304d402de 100644 --- a/src/Compilers/Core/Portable/Diagnostic/DiagnosticWithInfo.cs +++ b/src/Compilers/Core/Portable/Diagnostic/DiagnosticWithInfo.cs @@ -142,11 +142,6 @@ public override int GetHashCode() return Hash.Combine(this.Location.GetHashCode(), this.Info.GetHashCode()); } - public override bool Equals(object? obj) - { - return Equals(obj as Diagnostic); - } - public override bool Equals(Diagnostic? obj) { if (ReferenceEquals(this, obj)) diff --git a/src/Compilers/Core/Portable/Diagnostic/Diagnostic_SimpleDiagnostic.cs b/src/Compilers/Core/Portable/Diagnostic/Diagnostic_SimpleDiagnostic.cs index c4173d5306f57..ea1a1a02a7180 100644 --- a/src/Compilers/Core/Portable/Diagnostic/Diagnostic_SimpleDiagnostic.cs +++ b/src/Compilers/Core/Portable/Diagnostic/Diagnostic_SimpleDiagnostic.cs @@ -168,11 +168,6 @@ public override bool Equals(Diagnostic? obj) && _warningLevel == other._warningLevel; } - public override bool Equals(object? obj) - { - return this.Equals(obj as Diagnostic); - } - public override int GetHashCode() { return Hash.Combine(_descriptor, diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerConfigOptions.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerConfigOptions.cs index c9f9e0c539289..1e98c9cccb6ee 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerConfigOptions.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerConfigOptions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis.Diagnostics @@ -16,25 +15,9 @@ public abstract class AnalyzerConfigOptions /// public static StringComparer KeyComparer { get; } = AnalyzerConfig.Section.PropertiesKeyComparer; - internal static ImmutableDictionary EmptyDictionary = ImmutableDictionary.Create(KeyComparer); - /// /// Get an analyzer config value for the given key, using the . /// public abstract bool TryGetValue(string key, [NotNullWhen(true)] out string? value); } - - internal sealed class CompilerAnalyzerConfigOptions : AnalyzerConfigOptions - { - public static CompilerAnalyzerConfigOptions Empty { get; } = new CompilerAnalyzerConfigOptions(EmptyDictionary); - - private readonly ImmutableDictionary _backing; - - public CompilerAnalyzerConfigOptions(ImmutableDictionary properties) - { - _backing = properties; - } - - public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) => _backing.TryGetValue(key, out value); - } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs index cb89b1d2ac3a1..de8f06b696b73 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs @@ -2697,12 +2697,8 @@ ImmutableArray getOperationsToAnalyzeWithStackGuard(ImmutableArray GetSyntaxNodesToAnalyze( } Func? additionalFilter = semanticModel.GetSyntaxNodesToAnalyzeFilter(declaredNode, declaredSymbol); - bool shouldAddNode(SyntaxNode node) => (descendantDeclsToSkip == null || !descendantDeclsToSkip.Contains(node)) && (additionalFilter is null || additionalFilter(node)); var nodeBuilder = ArrayBuilder.GetInstance(); foreach (var node in declaredNode.DescendantNodesAndSelf(descendIntoChildren: shouldAddNode, descendIntoTrivia: true)) { if (shouldAddNode(node) && + !semanticModel.ShouldSkipSyntaxNodeAnalysis(node, declaredSymbol) && (!isPartialDeclAnalysis || analysisScope.ShouldAnalyze(node))) { nodeBuilder.Add(node); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs index b14db2b1619d0..22d5ca5db7c1f 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs @@ -1629,7 +1629,7 @@ internal static Diagnostic CreateAnalyzerExceptionDiagnostic(DiagnosticAnalyzer var analyzerName = analyzer.ToString(); var title = CodeAnalysisResources.CompilerAnalyzerFailure; var messageFormat = CodeAnalysisResources.CompilerAnalyzerThrows; - var contextInformation = string.Join(Environment.NewLine, CreateDiagnosticDescription(info, e), CreateDisablingMessage(analyzer)).Trim(); + var contextInformation = string.Join(Environment.NewLine, CreateDiagnosticDescription(info, e), CreateDisablingMessage(analyzer, analyzerName)).Trim(); var messageArguments = new[] { analyzerName, e.GetType().ToString(), e.Message, contextInformation }; var description = string.Format(CodeAnalysisResources.CompilerAnalyzerThrowsDescription, analyzerName, CreateDiagnosticDescription(info, e)); var descriptor = GetAnalyzerExceptionDiagnosticDescriptor(AnalyzerExceptionDiagnosticId, title, description, messageFormat); @@ -1647,21 +1647,23 @@ private static string CreateDiagnosticDescription(AnalysisContextInfo? info, Exc string.Format(CodeAnalysisResources.ExceptionContext, info?.GetContext()), e.CreateDiagnosticDescription()); } - private static string CreateDisablingMessage(DiagnosticAnalyzer analyzer) + private static string CreateDisablingMessage(DiagnosticAnalyzer analyzer, string analyzerName) { var diagnosticIds = ImmutableSortedSet.Empty.WithComparer(StringComparer.OrdinalIgnoreCase); try { foreach (var diagnostic in analyzer.SupportedDiagnostics) { - diagnosticIds = diagnosticIds.Add(diagnostic.Id); + // If a null diagnostic is returned, we would have already reported that to the user earlier; we can just skip this. + if (diagnostic != null) + { + diagnosticIds = diagnosticIds.Add(diagnostic.Id); + } } } -#pragma warning disable CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete; tracked by https://github.com/dotnet/roslyn/issues/58375 - catch (Exception e) when (FatalError.ReportIfNonFatalAndCatchUnlessCanceled(e)) -#pragma warning restore CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete + catch (Exception ex) { - // Intentionally empty + return string.Format(CodeAnalysisResources.CompilerAnalyzerThrowsDescription, analyzerName, ex.CreateDiagnosticDescription()); } if (diagnosticIds.IsEmpty) diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerOptionsExtensions.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerOptionsExtensions.cs index c0f2fda23b531..1ef1e3684300a 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerOptionsExtensions.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerOptionsExtensions.cs @@ -66,6 +66,10 @@ public static bool TryGetSeverityFromBulkConfiguration( if (analyzerConfigOptions.TryGetValue(categoryBasedKey, out var value) && AnalyzerConfigSet.TryParseSeverity(value, out severity)) { + // '/warnaserror' should bump Warning bulk configuration to Error. + if (severity == ReportDiagnostic.Warn && compilation.Options.GeneralDiagnosticOption == ReportDiagnostic.Error) + severity = ReportDiagnostic.Error; + return true; } @@ -74,6 +78,10 @@ public static bool TryGetSeverityFromBulkConfiguration( if (analyzerConfigOptions.TryGetValue(DotnetAnalyzerDiagnosticSeverityKey, out value) && AnalyzerConfigSet.TryParseSeverity(value, out severity)) { + // '/warnaserror' should bump Warning bulk configuration to Error. + if (severity == ReportDiagnostic.Warn && compilation.Options.GeneralDiagnosticOption == ReportDiagnostic.Error) + severity = ReportDiagnostic.Error; + return true; } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilerAnalyzerConfigOptionsProvider.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilerAnalyzerConfigOptionsProvider.cs index 3f095718378d3..373a04e94484e 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilerAnalyzerConfigOptionsProvider.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilerAnalyzerConfigOptionsProvider.cs @@ -13,7 +13,7 @@ internal sealed class CompilerAnalyzerConfigOptionsProvider : AnalyzerConfigOpti public static CompilerAnalyzerConfigOptionsProvider Empty { get; } = new CompilerAnalyzerConfigOptionsProvider( ImmutableDictionary.Empty, - CompilerAnalyzerConfigOptions.Empty); + DictionaryAnalyzerConfigOptions.Empty); internal CompilerAnalyzerConfigOptionsProvider( ImmutableDictionary treeDict, @@ -26,10 +26,10 @@ internal CompilerAnalyzerConfigOptionsProvider( public override AnalyzerConfigOptions GlobalOptions { get; } public override AnalyzerConfigOptions GetOptions(SyntaxTree tree) - => _treeDict.TryGetValue(tree, out var options) ? options : CompilerAnalyzerConfigOptions.Empty; + => _treeDict.TryGetValue(tree, out var options) ? options : DictionaryAnalyzerConfigOptions.Empty; public override AnalyzerConfigOptions GetOptions(AdditionalText textFile) - => _treeDict.TryGetValue(textFile, out var options) ? options : CompilerAnalyzerConfigOptions.Empty; + => _treeDict.TryGetValue(textFile, out var options) ? options : DictionaryAnalyzerConfigOptions.Empty; internal CompilerAnalyzerConfigOptionsProvider WithAdditionalTreeOptions(ImmutableDictionary treeDict) => new CompilerAnalyzerConfigOptionsProvider(_treeDict.AddRange(treeDict), GlobalOptions); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilerDiagnosticAnalyzer.CompilationAnalyzer.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilerDiagnosticAnalyzer.CompilationAnalyzer.cs index e2c9412c65e21..5a9eec83826de 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilerDiagnosticAnalyzer.CompilationAnalyzer.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilerDiagnosticAnalyzer.CompilationAnalyzer.cs @@ -104,11 +104,6 @@ public override string GetMessage(IFormatProvider? formatProvider = null) return _original.GetMessage(formatProvider); } - public override bool Equals(object? obj) - { - return _original.Equals(obj); - } - public override int GetHashCode() { return _original.GetHashCode(); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.Core.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.Core.cs index 79122a7e8270d..0a3718dc0ea45 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.Core.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.Core.cs @@ -54,6 +54,7 @@ internal class DefaultAnalyzerAssemblyLoader : AnalyzerAssemblyLoader "System.Runtime.CompilerServices.Unsafe", "System.Runtime.Extensions", "System.Runtime.InteropServices", + "System.Runtime.InteropServices.RuntimeInformation", "System.Runtime.Loader", "System.Runtime.Numerics", "System.Runtime.Serialization.Primitives", diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContextHelpers.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContextHelpers.cs index fc94f6825955d..0c214cb27a463 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContextHelpers.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticAnalysisContextHelpers.cs @@ -80,7 +80,7 @@ internal static void VerifyDiagnosticLocationsInCompilation(Diagnostic diagnosti { foreach (var location in diagnostic.AdditionalLocations) { - VerifyDiagnosticLocationInCompilation(diagnostic.Id, diagnostic.Location, compilation); + VerifyDiagnosticLocationInCompilation(diagnostic.Id, location, compilation); } } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DictionaryAnalyzerConfigOptions.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DictionaryAnalyzerConfigOptions.cs new file mode 100644 index 0000000000000..368b6c4176976 --- /dev/null +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DictionaryAnalyzerConfigOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.CodeAnalysis.Diagnostics +{ + internal sealed class DictionaryAnalyzerConfigOptions : AnalyzerConfigOptions + { + internal static readonly ImmutableDictionary EmptyDictionary = ImmutableDictionary.Create(KeyComparer); + + public static DictionaryAnalyzerConfigOptions Empty { get; } = new DictionaryAnalyzerConfigOptions(EmptyDictionary); + + internal readonly ImmutableDictionary Options; + + public DictionaryAnalyzerConfigOptions(ImmutableDictionary options) + => Options = options; + + public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) + => Options.TryGetValue(key, out value); + } +} diff --git a/src/Compilers/Core/Portable/Emit/AnonymousTypeKey.cs b/src/Compilers/Core/Portable/Emit/AnonymousTypeKey.cs index 2dca21ea50905..c862903532865 100644 --- a/src/Compilers/Core/Portable/Emit/AnonymousTypeKey.cs +++ b/src/Compilers/Core/Portable/Emit/AnonymousTypeKey.cs @@ -8,13 +8,12 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Emit { - internal struct AnonymousTypeKeyField : IEquatable + internal readonly struct AnonymousTypeKeyField : IEquatable { /// /// Name of the anonymous type field. @@ -61,7 +60,7 @@ public override int GetHashCode() } [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] - internal struct AnonymousTypeKey : IEquatable + internal readonly struct AnonymousTypeKey : IEquatable { internal readonly bool IsDelegate; internal readonly ImmutableArray Fields; @@ -97,7 +96,7 @@ private string GetDebuggerDisplay() { builder.Append("|"); } - builder.Append(this.Fields[i]); + builder.Append(this.Fields[i].Name); } return pooledBuilder.ToStringAndFree(); } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index 69244750636ea..4412a2bbbe4bf 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -217,7 +217,8 @@ internal EmitBaseline GetDelta(Compilation compilation, Guid encId, MetadataSize // Guid stream accumulates on the GUID heap unlike other heaps, so the previous generations are already included. guidStreamLengthAdded: metadataSizes.HeapSizes[(int)HeapIndex.Guid], anonymousTypeMap: ((IPEDeltaAssemblyBuilder)module).GetAnonymousTypeMap(), - synthesizedDelegates: ((IPEDeltaAssemblyBuilder)module).GetSynthesizedDelegates(), + anonymousDelegates: ((IPEDeltaAssemblyBuilder)module).GetAnonymousDelegates(), + anonymousDelegatesWithFixedTypes: ((IPEDeltaAssemblyBuilder)module).GetAnonymousDelegatesWithFixedTypes(), synthesizedMembers: synthesizedMembers, addedOrChangedMethods: AddRange(_previousGeneration.AddedOrChangedMethods, addedOrChangedMethodsByIndex), debugInformationProvider: _previousGeneration.DebugInformationProvider, diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs index 6f5560169c21d..760749f4ac1b6 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection.Metadata; @@ -63,9 +64,22 @@ public sealed class EmitBaseline internal sealed class MetadataSymbols { + /// + /// In C#, this is the set of anonymous types only; in VB, this is the set of anonymous types and delegates. + /// public readonly IReadOnlyDictionary AnonymousTypes; - public readonly IReadOnlyDictionary SynthesizedDelegates; + /// + /// In C#, the set of anonymous delegates where the parameter types and return type are + /// generic type arguments; in VB, this set is unused and empty. + /// + public readonly IReadOnlyDictionary AnonymousDelegates; + + /// + /// In C#, the set of anonymous delegates where at least one of the parameter types or return type + /// is not a valid type argument; in VB, this set is unused and empty. + /// + public readonly IReadOnlyDictionary AnonymousDelegatesWithFixedTypes; /// /// A map of the assembly identities of the baseline compilation to the identities of the original metadata AssemblyRefs. @@ -77,17 +91,20 @@ internal sealed class MetadataSymbols public MetadataSymbols( IReadOnlyDictionary anonymousTypes, - IReadOnlyDictionary synthesizedDelegates, + IReadOnlyDictionary anonymousDelegates, + IReadOnlyDictionary anonymousDelegatesWithFixedTypes, object metadataDecoder, ImmutableDictionary assemblyReferenceIdentityMap) { Debug.Assert(anonymousTypes != null); - Debug.Assert(synthesizedDelegates != null); + Debug.Assert(anonymousDelegates != null); + Debug.Assert(anonymousDelegatesWithFixedTypes != null); Debug.Assert(metadataDecoder != null); Debug.Assert(assemblyReferenceIdentityMap != null); this.AnonymousTypes = anonymousTypes; - this.SynthesizedDelegates = synthesizedDelegates; + this.AnonymousDelegates = anonymousDelegates; + this.AnonymousDelegatesWithFixedTypes = anonymousDelegatesWithFixedTypes; this.MetadataDecoder = metadataDecoder; this.AssemblyReferenceIdentityMap = assemblyReferenceIdentityMap; } @@ -229,7 +246,8 @@ public static EmitBaseline CreateInitialBaseline( userStringStreamLengthAdded: 0, guidStreamLengthAdded: 0, anonymousTypeMap: null, // Unset for initial metadata - synthesizedDelegates: null, // Unset for initial metadata + anonymousDelegates: null, // Unset for initial metadata + anonymousDelegatesWithFixedTypes: null, // Unset for initial metadata synthesizedMembers: ImmutableDictionary>.Empty, methodsAddedOrChanged: new Dictionary(), debugInformationProvider: debugInformationProvider, @@ -317,7 +335,8 @@ public static EmitBaseline CreateInitialBaseline( internal readonly IReadOnlyDictionary TypeToPropertyMap; internal readonly IReadOnlyDictionary MethodImpls; private readonly IReadOnlyDictionary? _anonymousTypeMap; - private readonly IReadOnlyDictionary? _synthesizedDelegates; + private readonly IReadOnlyDictionary? _anonymousDelegates; + private readonly IReadOnlyDictionary? _anonymousDelegatesWithFixedTypes; internal readonly ImmutableDictionary> SynthesizedMembers; private EmitBaseline( @@ -346,7 +365,8 @@ private EmitBaseline( int userStringStreamLengthAdded, int guidStreamLengthAdded, IReadOnlyDictionary? anonymousTypeMap, - IReadOnlyDictionary? synthesizedDelegates, + IReadOnlyDictionary? anonymousDelegates, + IReadOnlyDictionary? anonymousDelegatesWithFixedTypes, ImmutableDictionary> synthesizedMembers, IReadOnlyDictionary methodsAddedOrChanged, Func debugInformationProvider, @@ -359,7 +379,8 @@ private EmitBaseline( Debug.Assert((ordinal == 0) == (encId == default)); Debug.Assert((ordinal == 0) == (initialBaseline == null)); Debug.Assert((ordinal == 0) == (anonymousTypeMap == null)); - Debug.Assert((ordinal == 0) == (synthesizedDelegates == null)); + Debug.Assert((ordinal == 0) == (anonymousDelegates == null)); + Debug.Assert((ordinal == 0) == (anonymousDelegatesWithFixedTypes == null)); Debug.Assert(encId != module.GetModuleVersionId()); Debug.Assert(debugInformationProvider != null); Debug.Assert(localSignatureProvider != null); @@ -411,7 +432,8 @@ private EmitBaseline( UserStringStreamLengthAdded = userStringStreamLengthAdded; GuidStreamLengthAdded = guidStreamLengthAdded; _anonymousTypeMap = anonymousTypeMap; - _synthesizedDelegates = synthesizedDelegates; + _anonymousDelegates = anonymousDelegates; + _anonymousDelegatesWithFixedTypes = anonymousDelegatesWithFixedTypes; SynthesizedMembers = synthesizedMembers; AddedOrChangedMethods = methodsAddedOrChanged; @@ -445,7 +467,8 @@ internal EmitBaseline With( int userStringStreamLengthAdded, int guidStreamLengthAdded, IReadOnlyDictionary anonymousTypeMap, - IReadOnlyDictionary synthesizedDelegates, + IReadOnlyDictionary anonymousDelegates, + IReadOnlyDictionary anonymousDelegatesWithFixedTypes, ImmutableDictionary> synthesizedMembers, IReadOnlyDictionary addedOrChangedMethods, Func debugInformationProvider, @@ -454,8 +477,11 @@ internal EmitBaseline With( Debug.Assert(_anonymousTypeMap == null || anonymousTypeMap != null); Debug.Assert(_anonymousTypeMap == null || anonymousTypeMap.Count >= _anonymousTypeMap.Count); - Debug.Assert(_synthesizedDelegates == null || synthesizedDelegates != null); - Debug.Assert(_synthesizedDelegates == null || synthesizedDelegates.Count >= _synthesizedDelegates.Count); + Debug.Assert(_anonymousDelegates == null || anonymousDelegates != null); + Debug.Assert(_anonymousDelegates == null || anonymousDelegates.Count >= _anonymousDelegates.Count); + + Debug.Assert(_anonymousDelegatesWithFixedTypes == null || anonymousDelegatesWithFixedTypes != null); + Debug.Assert(_anonymousDelegatesWithFixedTypes == null || anonymousDelegatesWithFixedTypes.Count >= _anonymousDelegatesWithFixedTypes.Count); return new EmitBaseline( InitialBaseline, @@ -483,7 +509,8 @@ internal EmitBaseline With( userStringStreamLengthAdded: userStringStreamLengthAdded, guidStreamLengthAdded: guidStreamLengthAdded, anonymousTypeMap: anonymousTypeMap, - synthesizedDelegates: synthesizedDelegates, + anonymousDelegates: anonymousDelegates, + anonymousDelegatesWithFixedTypes: anonymousDelegatesWithFixedTypes, synthesizedMembers: synthesizedMembers, methodsAddedOrChanged: addedOrChangedMethods, debugInformationProvider: debugInformationProvider, @@ -503,23 +530,38 @@ internal IReadOnlyDictionary AnonymousType return _anonymousTypeMap; } - RoslynDebug.AssertNotNull(LazyMetadataSymbols); + Debug.Assert(LazyMetadataSymbols is object); return LazyMetadataSymbols.AnonymousTypes; } } - internal IReadOnlyDictionary SynthesizedDelegates + internal IReadOnlyDictionary AnonymousDelegates + { + get + { + if (Ordinal > 0) + { + Debug.Assert(_anonymousDelegates is object); + return _anonymousDelegates; + } + + Debug.Assert(LazyMetadataSymbols is object); + return LazyMetadataSymbols.AnonymousDelegates; + } + } + + internal IReadOnlyDictionary AnonymousDelegatesWithFixedTypes { get { if (Ordinal > 0) { - Debug.Assert(_synthesizedDelegates is not null); - return _synthesizedDelegates; + Debug.Assert(_anonymousDelegatesWithFixedTypes is object); + return _anonymousDelegatesWithFixedTypes; } - RoslynDebug.AssertNotNull(LazyMetadataSymbols); - return LazyMetadataSymbols.SynthesizedDelegates; + Debug.Assert(LazyMetadataSymbols is object); + return LazyMetadataSymbols.AnonymousDelegatesWithFixedTypes; } } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/IPEDeltaAssemblyBuilder.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/IPEDeltaAssemblyBuilder.cs index c968ea595379a..874b70f450104 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/IPEDeltaAssemblyBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/IPEDeltaAssemblyBuilder.cs @@ -10,6 +10,7 @@ internal interface IPEDeltaAssemblyBuilder { void OnCreatedIndices(DiagnosticBag diagnostics); IReadOnlyDictionary GetAnonymousTypeMap(); - IReadOnlyDictionary GetSynthesizedDelegates(); + IReadOnlyDictionary GetAnonymousDelegates(); + IReadOnlyDictionary GetAnonymousDelegatesWithFixedTypes(); } } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs index 75ae6c2ee81c4..9748a92841ec3 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolMatcher.cs @@ -61,7 +61,8 @@ public EmitBaseline MapBaselineToCompilation( userStringStreamLengthAdded: baseline.UserStringStreamLengthAdded, guidStreamLengthAdded: baseline.GuidStreamLengthAdded, anonymousTypeMap: MapAnonymousTypes(baseline.AnonymousTypeMap), - synthesizedDelegates: MapSynthesizedDelegates(baseline.SynthesizedDelegates), + anonymousDelegates: MapAnonymousDelegates(baseline.AnonymousDelegates), + anonymousDelegatesWithFixedTypes: MapAnonymousDelegatesWithFixedTypes(baseline.AnonymousDelegatesWithFixedTypes), synthesizedMembers: mappedSynthesizedMembers, addedOrChangedMethods: MapAddedOrChangedMethods(baseline.AddedOrChangedMethods), debugInformationProvider: baseline.DebugInformationProvider, @@ -114,11 +115,11 @@ private IReadOnlyDictionary MapAnonymousTy return result; } - private IReadOnlyDictionary MapSynthesizedDelegates(IReadOnlyDictionary synthesizedDelegates) + private IReadOnlyDictionary MapAnonymousDelegates(IReadOnlyDictionary anonymousDelegates) { var result = new Dictionary(); - foreach (var (key, value) in synthesizedDelegates) + foreach (var (key, value) in anonymousDelegates) { var delegateTypeDef = (Cci.ITypeDefinition?)MapDefinition(value.Delegate); RoslynDebug.Assert(delegateTypeDef != null); @@ -128,6 +129,20 @@ private IReadOnlyDictionary Ma return result; } + private IReadOnlyDictionary MapAnonymousDelegatesWithFixedTypes(IReadOnlyDictionary anonymousDelegates) + { + var result = new Dictionary(); + + foreach (var (key, value) in anonymousDelegates) + { + var type = (Cci.ITypeDefinition?)MapDefinition(value.Type); + RoslynDebug.Assert(type != null); + result.Add(key, new AnonymousTypeValue(value.Name, value.UniqueIndex, type)); + } + + return result; + } + /// /// Merges synthesized members generated during lowering of the current compilation with aggregate synthesized members /// from all previous source generations (gen >= 1). diff --git a/src/Compilers/Core/Portable/Generated/Operations.Generated.cs b/src/Compilers/Core/Portable/Generated/Operations.Generated.cs index 5284d803ab5be..1cbfb70d533b2 100644 --- a/src/Compilers/Core/Portable/Generated/Operations.Generated.cs +++ b/src/Compilers/Core/Portable/Generated/Operations.Generated.cs @@ -3552,14 +3552,16 @@ internal BlockOperation(ImmutableArray operations, ImmutableArray Operations { get; } public ImmutableArray Locals { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Operations.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Operations.Length => Operations[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -3575,6 +3577,22 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Operations.IsEmpty) return (true, 0, Operations.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Block; @@ -3589,14 +3607,16 @@ internal VariableDeclarationGroupOperation(ImmutableArray Declarations { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Declarations.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Declarations.Length => Declarations[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -3612,6 +3632,22 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Declarations.IsEmpty) return (true, 0, Declarations.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.VariableDeclarationGroup; @@ -3632,7 +3668,10 @@ internal SwitchOperation(ImmutableArray locals, IOperation value, public IOperation Value { get; } public ImmutableArray Cases { get; } public ILabelSymbol ExitLabel { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1) + + Cases.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null @@ -3641,7 +3680,7 @@ 1 when index < Cases.Length => Cases[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -3660,6 +3699,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Cases.IsEmpty) return (true, 1, Cases.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Switch; @@ -3698,7 +3756,12 @@ internal ForEachLoopOperation(IOperation loopControlVariable, IOperation collect public ImmutableArray NextVariables { get; } public ForEachLoopOperationInfo? Info { get; } public bool IsAsynchronous { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (LoopControlVariable is null ? 0 : 1) + + (Collection is null ? 0 : 1) + + NextVariables.Length + + (Body is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Collection != null @@ -3711,7 +3774,7 @@ 3 when index < NextVariables.Length => NextVariables[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -3736,6 +3799,31 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!NextVariables.IsEmpty) return (true, 3, NextVariables.Length - 1); + else goto case 3; + case 3 when previousIndex > 0: + return (true, 3, previousIndex - 1); + case 3: + if (Body != null) return (true, 2, 0); + else goto case 2; + case 2: + if (LoopControlVariable != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Collection != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Loop; @@ -3756,7 +3844,12 @@ internal ForLoopOperation(ImmutableArray before, ImmutableArray ConditionLocals { get; } public IOperation? Condition { get; } public ImmutableArray AtLoopBottom { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Before.Length + + (Condition is null ? 0 : 1) + + AtLoopBottom.Length + + (Body is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Before.Length @@ -3769,7 +3862,7 @@ 3 when index < AtLoopBottom.Length => AtLoopBottom[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -3796,6 +3889,33 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!AtLoopBottom.IsEmpty) return (true, 3, AtLoopBottom.Length - 1); + else goto case 3; + case 3 when previousIndex > 0: + return (true, 3, previousIndex - 1); + case 3: + if (Body != null) return (true, 2, 0); + else goto case 2; + case 2: + if (Condition != null) return (true, 1, 0); + else goto case 1; + case 1: + if (!Before.IsEmpty) return (true, 0, Before.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Loop; @@ -3822,7 +3942,14 @@ internal ForToLoopOperation(IOperation loopControlVariable, IOperation initialVa public bool IsChecked { get; } public ImmutableArray NextVariables { get; } public (ILocalSymbol LoopObject, ForToLoopOperationUserDefinedInfo UserDefinedInfo) Info { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (LoopControlVariable is null ? 0 : 1) + + (InitialValue is null ? 0 : 1) + + (LimitValue is null ? 0 : 1) + + (StepValue is null ? 0 : 1) + + NextVariables.Length + + (Body is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when LoopControlVariable != null @@ -3839,7 +3966,7 @@ 5 when index < NextVariables.Length => NextVariables[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -3870,6 +3997,37 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!NextVariables.IsEmpty) return (true, 5, NextVariables.Length - 1); + else goto case 5; + case 5 when previousIndex > 0: + return (true, 5, previousIndex - 1); + case 5: + if (Body != null) return (true, 4, 0); + else goto case 4; + case 4: + if (StepValue != null) return (true, 3, 0); + else goto case 3; + case 3: + if (LimitValue != null) return (true, 2, 0); + else goto case 2; + case 2: + if (InitialValue != null) return (true, 1, 0); + else goto case 1; + case 1: + if (LoopControlVariable != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Loop; @@ -3890,6 +4048,10 @@ internal WhileLoopOperation(IOperation? condition, bool conditionIsTop, bool con public bool ConditionIsTop { get; } public bool ConditionIsUntil { get; } public IOperation? IgnoredCondition { get; } + internal override int ChildOperationsCount => + (Condition is null ? 0 : 1) + + (IgnoredCondition is null ? 0 : 1) + + (Body is null ? 0 : 1); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Loop; @@ -3906,14 +4068,16 @@ internal LabeledOperation(ILabelSymbol label, IOperation? operation, SemanticMod } public ILabelSymbol Label { get; } public IOperation? Operation { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operation is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operation != null => Operation, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -3927,6 +4091,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Operation != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Labeled; @@ -3943,8 +4121,10 @@ internal BranchOperation(ILabelSymbol target, BranchKind branchKind, SemanticMod } public ILabelSymbol Target { get; } public BranchKind BranchKind { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Branch; @@ -3955,8 +4135,10 @@ internal sealed partial class EmptyOperation : Operation, IEmptyOperation { internal EmptyOperation(SemanticModel? semanticModel, SyntaxNode syntax, bool isImplicit) : base(semanticModel, syntax, isImplicit) { } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Empty; @@ -3972,14 +4154,16 @@ internal ReturnOperation(IOperation? returnedValue, OperationKind kind, Semantic Kind = kind; } public IOperation? ReturnedValue { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (ReturnedValue is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when ReturnedValue != null => ReturnedValue, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -3993,6 +4177,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (ReturnedValue != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind { get; } @@ -4011,7 +4209,10 @@ internal LockOperation(IOperation lockedValue, IOperation body, ILocalSymbol? lo public IOperation LockedValue { get; } public IOperation Body { get; } public ILocalSymbol? LockTakenSymbol { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (LockedValue is null ? 0 : 1) + + (Body is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when LockedValue != null @@ -4020,7 +4221,7 @@ protected override IOperation GetCurrent(int slot, int index) => Body, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4037,6 +4238,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Body != null) return (true, 1, 0); + else goto case 1; + case 1: + if (LockedValue != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Lock; @@ -4057,7 +4275,11 @@ internal TryOperation(IBlockOperation body, ImmutableArray Catches { get; } public IBlockOperation? Finally { get; } public ILabelSymbol? ExitLabel { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Body is null ? 0 : 1) + + Catches.Length + + (Finally is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Body != null @@ -4068,7 +4290,7 @@ 1 when index < Catches.Length => Finally, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4090,6 +4312,28 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Finally != null) return (true, 2, 0); + else goto case 2; + case 2: + if (!Catches.IsEmpty) return (true, 1, Catches.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (Body != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Try; @@ -4112,7 +4356,10 @@ internal UsingOperation(IOperation resources, IOperation body, ImmutableArray Locals { get; } public bool IsAsynchronous { get; } public DisposeOperationInfo DisposeInfo { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Resources is null ? 0 : 1) + + (Body is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Resources != null @@ -4121,7 +4368,7 @@ protected override IOperation GetCurrent(int slot, int index) => Body, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4138,6 +4385,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Body != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Resources != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Using; @@ -4152,14 +4416,16 @@ internal ExpressionStatementOperation(IOperation operation, SemanticModel? seman Operation = SetParentOperation(operation, this); } public IOperation Operation { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operation is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operation != null => Operation, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4173,6 +4439,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Operation != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ExpressionStatement; @@ -4191,7 +4471,10 @@ internal LocalFunctionOperation(IMethodSymbol symbol, IBlockOperation? body, IBl public IMethodSymbol Symbol { get; } public IBlockOperation? Body { get; } public IBlockOperation? IgnoredBody { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Body is null ? 0 : 1) + + (IgnoredBody is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Body != null @@ -4200,7 +4483,7 @@ protected override IOperation GetCurrent(int slot, int index) => IgnoredBody, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4217,6 +4500,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (IgnoredBody != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Body != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.LocalFunction; @@ -4227,8 +4527,10 @@ internal sealed partial class StopOperation : Operation, IStopOperation { internal StopOperation(SemanticModel? semanticModel, SyntaxNode syntax, bool isImplicit) : base(semanticModel, syntax, isImplicit) { } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Stop; @@ -4239,8 +4541,10 @@ internal sealed partial class EndOperation : Operation, IEndOperation { internal EndOperation(SemanticModel? semanticModel, SyntaxNode syntax, bool isImplicit) : base(semanticModel, syntax, isImplicit) { } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.End; @@ -4257,7 +4561,10 @@ internal RaiseEventOperation(IEventReferenceOperation eventReference, ImmutableA } public IEventReferenceOperation EventReference { get; } public ImmutableArray Arguments { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (EventReference is null ? 0 : 1) + + Arguments.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when EventReference != null @@ -4266,7 +4573,7 @@ 1 when index < Arguments.Length => Arguments[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4285,6 +4592,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Arguments.IsEmpty) return (true, 1, Arguments.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (EventReference != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.RaiseEvent; @@ -4299,8 +4625,10 @@ internal LiteralOperation(SemanticModel? semanticModel, SyntaxNode syntax, IType OperationConstantValue = constantValue; Type = type; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.Literal; @@ -4324,14 +4652,16 @@ internal ConversionOperation(IOperation operand, IConvertibleConversion conversi public CommonConversion Conversion => ConversionConvertible.ToCommonConversion(); public bool IsTryCast { get; } public bool IsChecked { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operand is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operand != null => Operand, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4345,6 +4675,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Operand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.Conversion; @@ -4366,7 +4710,10 @@ internal InvocationOperation(IMethodSymbol targetMethod, IOperation? instance, b public IOperation? Instance { get; } public bool IsVirtual { get; } public ImmutableArray Arguments { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Instance is null ? 0 : 1) + + Arguments.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Instance != null @@ -4375,7 +4722,7 @@ 1 when index < Arguments.Length => Arguments[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4394,6 +4741,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Arguments.IsEmpty) return (true, 1, Arguments.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (Instance != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Invocation; @@ -4411,7 +4777,10 @@ internal ArrayElementReferenceOperation(IOperation arrayReference, ImmutableArra } public IOperation ArrayReference { get; } public ImmutableArray Indices { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (ArrayReference is null ? 0 : 1) + + Indices.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when ArrayReference != null @@ -4420,7 +4789,7 @@ 1 when index < Indices.Length => Indices[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4439,6 +4808,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Indices.IsEmpty) return (true, 1, Indices.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (ArrayReference != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ArrayElementReference; @@ -4457,8 +4845,10 @@ internal LocalReferenceOperation(ILocalSymbol local, bool isDeclaration, Semanti } public ILocalSymbol Local { get; } public bool IsDeclaration { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.LocalReference; @@ -4474,8 +4864,10 @@ internal ParameterReferenceOperation(IParameterSymbol parameter, SemanticModel? Type = type; } public IParameterSymbol Parameter { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ParameterReference; @@ -4503,14 +4895,16 @@ internal FieldReferenceOperation(IFieldSymbol field, bool isDeclaration, IOperat } public IFieldSymbol Field { get; } public bool IsDeclaration { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Instance is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Instance != null => Instance, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4524,6 +4918,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Instance != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.FieldReference; @@ -4541,14 +4949,16 @@ internal MethodReferenceOperation(IMethodSymbol method, bool isVirtual, IOperati } public IMethodSymbol Method { get; } public bool IsVirtual { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Instance is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Instance != null => Instance, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4562,15 +4972,29 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } - public override ITypeSymbol? Type { get; } - internal override ConstantValue? OperationConstantValue => null; - public override OperationKind Kind => OperationKind.MethodReference; - public override void Accept(OperationVisitor visitor) => visitor.VisitMethodReference(this); - public override TResult? Accept(OperationVisitor visitor, TArgument argument) where TResult : default => visitor.VisitMethodReference(this, argument); - } - internal sealed partial class PropertyReferenceOperation : BaseMemberReferenceOperation, IPropertyReferenceOperation - { - internal PropertyReferenceOperation(IPropertySymbol property, ImmutableArray arguments, IOperation? instance, SemanticModel? semanticModel, SyntaxNode syntax, ITypeSymbol? type, bool isImplicit) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Instance != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } + public override ITypeSymbol? Type { get; } + internal override ConstantValue? OperationConstantValue => null; + public override OperationKind Kind => OperationKind.MethodReference; + public override void Accept(OperationVisitor visitor) => visitor.VisitMethodReference(this); + public override TResult? Accept(OperationVisitor visitor, TArgument argument) where TResult : default => visitor.VisitMethodReference(this, argument); + } + internal sealed partial class PropertyReferenceOperation : BaseMemberReferenceOperation, IPropertyReferenceOperation + { + internal PropertyReferenceOperation(IPropertySymbol property, ImmutableArray arguments, IOperation? instance, SemanticModel? semanticModel, SyntaxNode syntax, ITypeSymbol? type, bool isImplicit) : base(instance, semanticModel, syntax, isImplicit) { Property = property; @@ -4579,7 +5003,10 @@ internal PropertyReferenceOperation(IPropertySymbol property, ImmutableArray Arguments { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Arguments.Length + + (Instance is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Instance != null @@ -4588,7 +5015,7 @@ 1 when index < Arguments.Length => Arguments[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4607,6 +5034,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Arguments.IsEmpty) return (true, 1, Arguments.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (Instance != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.PropertyReference; @@ -4622,14 +5068,16 @@ internal EventReferenceOperation(IEventSymbol @event, IOperation? instance, Sema Type = type; } public IEventSymbol Event { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Instance is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Instance != null => Instance, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4643,6 +5091,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Instance != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.EventReference; @@ -4667,14 +5129,16 @@ internal UnaryOperation(UnaryOperatorKind operatorKind, IOperation operand, bool public bool IsLifted { get; } public bool IsChecked { get; } public IMethodSymbol? OperatorMethod { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operand is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operand != null => Operand, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4688,6 +5152,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Operand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.Unary; @@ -4718,7 +5196,10 @@ internal BinaryOperation(BinaryOperatorKind operatorKind, IOperation leftOperand public bool IsCompareText { get; } public IMethodSymbol? OperatorMethod { get; } public IMethodSymbol? UnaryOperatorMethod { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (LeftOperand is null ? 0 : 1) + + (RightOperand is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when LeftOperand != null @@ -4727,7 +5208,7 @@ protected override IOperation GetCurrent(int slot, int index) => RightOperand, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4744,6 +5225,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (RightOperand != null) return (true, 1, 0); + else goto case 1; + case 1: + if (LeftOperand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.Binary; @@ -4766,7 +5264,11 @@ internal ConditionalOperation(IOperation condition, IOperation whenTrue, IOperat public IOperation WhenTrue { get; } public IOperation? WhenFalse { get; } public bool IsRef { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Condition is null ? 0 : 1) + + (WhenTrue is null ? 0 : 1) + + (WhenFalse is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Condition != null @@ -4777,7 +5279,7 @@ protected override IOperation GetCurrent(int slot, int index) => WhenFalse, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4797,6 +5299,26 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (WhenFalse != null) return (true, 2, 0); + else goto case 2; + case 2: + if (WhenTrue != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Condition != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.Conditional; @@ -4818,7 +5340,10 @@ internal CoalesceOperation(IOperation value, IOperation whenNull, IConvertibleCo public IOperation WhenNull { get; } internal IConvertibleConversion ValueConversionConvertible { get; } public CommonConversion ValueConversion => ValueConversionConvertible.ToCommonConversion(); - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1) + + (WhenNull is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null @@ -4827,7 +5352,7 @@ protected override IOperation GetCurrent(int slot, int index) => WhenNull, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4844,6 +5369,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (WhenNull != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.Coalesce; @@ -4860,14 +5402,16 @@ internal AnonymousFunctionOperation(IMethodSymbol symbol, IBlockOperation body, } public IMethodSymbol Symbol { get; } public IBlockOperation Body { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Body is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Body != null => Body, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4881,6 +5425,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Body != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.AnonymousFunction; @@ -4901,7 +5459,10 @@ internal ObjectCreationOperation(IMethodSymbol? constructor, IObjectOrCollection public IMethodSymbol? Constructor { get; } public IObjectOrCollectionInitializerOperation? Initializer { get; } public ImmutableArray Arguments { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Initializer is null ? 0 : 1) + + Arguments.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Arguments.Length @@ -4910,7 +5471,7 @@ 0 when index < Arguments.Length => Initializer, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4929,6 +5490,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Initializer != null) return (true, 1, 0); + else goto case 1; + case 1: + if (!Arguments.IsEmpty) return (true, 0, Arguments.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.ObjectCreation; @@ -4944,14 +5524,16 @@ internal TypeParameterObjectCreationOperation(IObjectOrCollectionInitializerOper Type = type; } public IObjectOrCollectionInitializerOperation? Initializer { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Initializer is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Initializer != null => Initializer, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -4965,6 +5547,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Initializer != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.TypeParameterObjectCreation; @@ -4982,7 +5578,10 @@ internal ArrayCreationOperation(ImmutableArray dimensionSizes, IArra } public ImmutableArray DimensionSizes { get; } public IArrayInitializerOperation? Initializer { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + DimensionSizes.Length + + (Initializer is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < DimensionSizes.Length @@ -4991,7 +5590,7 @@ 0 when index < DimensionSizes.Length => Initializer, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5010,6 +5609,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Initializer != null) return (true, 1, 0); + else goto case 1; + case 1: + if (!DimensionSizes.IsEmpty) return (true, 0, DimensionSizes.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ArrayCreation; @@ -5025,8 +5643,10 @@ internal InstanceReferenceOperation(InstanceReferenceKind referenceKind, Semanti Type = type; } public InstanceReferenceKind ReferenceKind { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.InstanceReference; @@ -5046,14 +5666,16 @@ internal IsTypeOperation(IOperation valueOperand, ITypeSymbol typeOperand, bool public IOperation ValueOperand { get; } public ITypeSymbol TypeOperand { get; } public bool IsNegated { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (ValueOperand is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when ValueOperand != null => ValueOperand, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5067,6 +5689,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (ValueOperand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.IsType; @@ -5082,14 +5718,16 @@ internal AwaitOperation(IOperation operation, SemanticModel? semanticModel, Synt Type = type; } public IOperation Operation { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operation is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operation != null => Operation, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5103,6 +5741,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Operation != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Await; @@ -5130,7 +5782,10 @@ internal SimpleAssignmentOperation(bool isRef, IOperation target, IOperation val Type = type; } public bool IsRef { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Target is null ? 0 : 1) + + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Target != null @@ -5139,7 +5794,7 @@ protected override IOperation GetCurrent(int slot, int index) => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5156,6 +5811,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Target != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.SimpleAssignment; @@ -5183,7 +5855,10 @@ internal CompoundAssignmentOperation(IConvertibleConversion inConversion, IConve public bool IsLifted { get; } public bool IsChecked { get; } public IMethodSymbol? OperatorMethod { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Target is null ? 0 : 1) + + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Target != null @@ -5192,7 +5867,7 @@ protected override IOperation GetCurrent(int slot, int index) => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5209,6 +5884,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Target != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.CompoundAssignment; @@ -5225,14 +5917,16 @@ internal ParenthesizedOperation(IOperation operand, SemanticModel? semanticModel Type = type; } public IOperation Operand { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operand is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operand != null => Operand, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5246,6 +5940,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Operand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.Parenthesized; @@ -5265,7 +5973,10 @@ internal EventAssignmentOperation(IOperation eventReference, IOperation handlerV public IOperation EventReference { get; } public IOperation HandlerValue { get; } public bool Adds { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (EventReference is null ? 0 : 1) + + (HandlerValue is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when EventReference != null @@ -5274,7 +5985,7 @@ protected override IOperation GetCurrent(int slot, int index) => HandlerValue, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5291,6 +6002,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (HandlerValue != null) return (true, 1, 0); + else goto case 1; + case 1: + if (EventReference != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.EventAssignment; @@ -5308,7 +6036,10 @@ internal ConditionalAccessOperation(IOperation operation, IOperation whenNotNull } public IOperation Operation { get; } public IOperation WhenNotNull { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operation is null ? 0 : 1) + + (WhenNotNull is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operation != null @@ -5317,7 +6048,7 @@ protected override IOperation GetCurrent(int slot, int index) => WhenNotNull, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5334,6 +6065,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (WhenNotNull != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Operation != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ConditionalAccess; @@ -5347,8 +6095,10 @@ internal ConditionalAccessInstanceOperation(SemanticModel? semanticModel, Syntax { Type = type; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ConditionalAccessInstance; @@ -5365,14 +6115,16 @@ internal InterpolatedStringOperation(ImmutableArray Parts { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Parts.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Parts.Length => Parts[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5388,6 +6140,22 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Parts.IsEmpty) return (true, 0, Parts.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.InterpolatedString; @@ -5403,14 +6171,16 @@ internal AnonymousObjectCreationOperation(ImmutableArray initializer Type = type; } public ImmutableArray Initializers { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Initializers.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Initializers.Length => Initializers[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5426,6 +6196,22 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Initializers.IsEmpty) return (true, 0, Initializers.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.AnonymousObjectCreation; @@ -5441,14 +6227,16 @@ internal ObjectOrCollectionInitializerOperation(ImmutableArray initi Type = type; } public ImmutableArray Initializers { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Initializers.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Initializers.Length => Initializers[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5464,6 +6252,22 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Initializers.IsEmpty) return (true, 0, Initializers.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ObjectOrCollectionInitializer; @@ -5481,7 +6285,10 @@ internal MemberInitializerOperation(IOperation initializedMember, IObjectOrColle } public IOperation InitializedMember { get; } public IObjectOrCollectionInitializerOperation Initializer { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (InitializedMember is null ? 0 : 1) + + (Initializer is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when InitializedMember != null @@ -5490,7 +6297,7 @@ protected override IOperation GetCurrent(int slot, int index) => Initializer, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5507,6 +6314,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Initializer != null) return (true, 1, 0); + else goto case 1; + case 1: + if (InitializedMember != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.MemberInitializer; @@ -5523,14 +6347,16 @@ internal NameOfOperation(IOperation argument, SemanticModel? semanticModel, Synt Type = type; } public IOperation Argument { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Argument is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Argument != null => Argument, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5544,6 +6370,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Argument != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.NameOf; @@ -5561,14 +6401,16 @@ internal TupleOperation(ImmutableArray elements, ITypeSymbol? natura } public ImmutableArray Elements { get; } public ITypeSymbol? NaturalType { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Elements.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Elements.Length => Elements[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5584,6 +6426,22 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Elements.IsEmpty) return (true, 0, Elements.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Tuple; @@ -5605,14 +6463,16 @@ internal DynamicMemberReferenceOperation(IOperation? instance, string memberName public string MemberName { get; } public ImmutableArray TypeArguments { get; } public ITypeSymbol? ContainingType { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Instance is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Instance != null => Instance, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5626,6 +6486,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Instance != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.DynamicMemberReference; @@ -5641,14 +6515,16 @@ internal TranslatedQueryOperation(IOperation operation, SemanticModel? semanticM Type = type; } public IOperation Operation { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operation is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operation != null => Operation, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5662,6 +6538,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Operation != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.TranslatedQuery; @@ -5677,14 +6567,16 @@ internal DelegateCreationOperation(IOperation target, SemanticModel? semanticMod Type = type; } public IOperation Target { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Target is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Target != null => Target, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5698,6 +6590,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Target != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.DelegateCreation; @@ -5712,8 +6618,10 @@ internal DefaultValueOperation(SemanticModel? semanticModel, SyntaxNode syntax, OperationConstantValue = constantValue; Type = type; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.DefaultValue; @@ -5729,8 +6637,10 @@ internal TypeOfOperation(ITypeSymbol typeOperand, SemanticModel? semanticModel, Type = type; } public ITypeSymbol TypeOperand { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.TypeOf; @@ -5747,8 +6657,10 @@ internal SizeOfOperation(ITypeSymbol typeOperand, SemanticModel? semanticModel, Type = type; } public ITypeSymbol TypeOperand { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.SizeOf; @@ -5764,14 +6676,16 @@ internal AddressOfOperation(IOperation reference, SemanticModel? semanticModel, Type = type; } public IOperation Reference { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Reference is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Reference != null => Reference, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5785,6 +6699,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Reference != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.AddressOf; @@ -5802,7 +6730,10 @@ internal IsPatternOperation(IOperation value, IPatternOperation pattern, Semanti } public IOperation Value { get; } public IPatternOperation Pattern { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1) + + (Pattern is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null @@ -5811,7 +6742,7 @@ protected override IOperation GetCurrent(int slot, int index) => Pattern, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5828,6 +6759,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Pattern != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.IsPattern; @@ -5852,14 +6800,16 @@ internal IncrementOrDecrementOperation(bool isPostfix, bool isLifted, bool isChe public bool IsChecked { get; } public IOperation Target { get; } public IMethodSymbol? OperatorMethod { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Target is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Target != null => Target, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5873,6 +6823,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Target != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind { get; } @@ -5888,14 +6852,16 @@ internal ThrowOperation(IOperation? exception, SemanticModel? semanticModel, Syn Type = type; } public IOperation? Exception { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Exception is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Exception != null => Exception, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5909,6 +6875,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Exception != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Throw; @@ -5922,7 +6902,10 @@ internal DeconstructionAssignmentOperation(IOperation target, IOperation value, { Type = type; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Target is null ? 0 : 1) + + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Target != null @@ -5931,7 +6914,7 @@ protected override IOperation GetCurrent(int slot, int index) => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5948,6 +6931,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Target != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.DeconstructionAssignment; @@ -5963,14 +6963,16 @@ internal DeclarationExpressionOperation(IOperation expression, SemanticModel? se Type = type; } public IOperation Expression { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Expression is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Expression != null => Expression, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -5984,6 +6986,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Expression != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.DeclarationExpression; @@ -5997,8 +7013,10 @@ internal OmittedArgumentOperation(SemanticModel? semanticModel, SyntaxNode synta { Type = type; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.OmittedArgument; @@ -6024,14 +7042,16 @@ internal FieldInitializerOperation(ImmutableArray initializedField InitializedFields = initializedFields; } public ImmutableArray InitializedFields { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6045,6 +7065,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.FieldInitializer; @@ -6055,14 +7089,16 @@ internal sealed partial class VariableInitializerOperation : BaseSymbolInitializ { internal VariableInitializerOperation(ImmutableArray locals, IOperation value, SemanticModel? semanticModel, SyntaxNode syntax, bool isImplicit) : base(locals, value, semanticModel, syntax, isImplicit) { } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6076,6 +7112,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.VariableInitializer; @@ -6090,14 +7140,16 @@ internal PropertyInitializerOperation(ImmutableArray initialize InitializedProperties = initializedProperties; } public ImmutableArray InitializedProperties { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6111,6 +7163,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.PropertyInitializer; @@ -6125,14 +7191,16 @@ internal ParameterInitializerOperation(IParameterSymbol parameter, ImmutableArra Parameter = parameter; } public IParameterSymbol Parameter { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6146,6 +7214,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ParameterInitializer; @@ -6160,14 +7242,16 @@ internal ArrayInitializerOperation(ImmutableArray elementValues, Sem ElementValues = SetParentOperation(elementValues, this); } public ImmutableArray ElementValues { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + ElementValues.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < ElementValues.Length => ElementValues[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6183,6 +7267,22 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!ElementValues.IsEmpty) return (true, 0, ElementValues.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ArrayInitializer; @@ -6201,7 +7301,10 @@ internal VariableDeclaratorOperation(ILocalSymbol symbol, IVariableInitializerOp public ILocalSymbol Symbol { get; } public IVariableInitializerOperation? Initializer { get; } public ImmutableArray IgnoredArguments { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Initializer is null ? 0 : 1) + + IgnoredArguments.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < IgnoredArguments.Length @@ -6210,7 +7313,7 @@ 0 when index < IgnoredArguments.Length => Initializer, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6229,6 +7332,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Initializer != null) return (true, 1, 0); + else goto case 1; + case 1: + if (!IgnoredArguments.IsEmpty) return (true, 0, IgnoredArguments.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.VariableDeclarator; @@ -6247,7 +7369,11 @@ internal VariableDeclarationOperation(ImmutableArray Declarators { get; } public IVariableInitializerOperation? Initializer { get; } public ImmutableArray IgnoredDimensions { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Declarators.Length + + (Initializer is null ? 0 : 1) + + IgnoredDimensions.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < IgnoredDimensions.Length @@ -6258,7 +7384,7 @@ 1 when index < Declarators.Length => Initializer, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6282,6 +7408,30 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Initializer != null) return (true, 2, 0); + else goto case 2; + case 2: + if (!Declarators.IsEmpty) return (true, 1, Declarators.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (!IgnoredDimensions.IsEmpty) return (true, 0, IgnoredDimensions.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.VariableDeclaration; @@ -6306,14 +7456,16 @@ internal ArgumentOperation(ArgumentKind argumentKind, IParameterSymbol? paramete public CommonConversion InConversion => InConversionConvertible.ToCommonConversion(); internal IConvertibleConversion OutConversionConvertible { get; } public CommonConversion OutConversion => OutConversionConvertible.ToCommonConversion(); - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6327,6 +7479,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Argument; @@ -6349,7 +7515,11 @@ internal CatchClauseOperation(IOperation? exceptionDeclarationOrExpression, ITyp public ImmutableArray Locals { get; } public IOperation? Filter { get; } public IBlockOperation Handler { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (ExceptionDeclarationOrExpression is null ? 0 : 1) + + (Filter is null ? 0 : 1) + + (Handler is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when ExceptionDeclarationOrExpression != null @@ -6360,7 +7530,7 @@ protected override IOperation GetCurrent(int slot, int index) => Handler, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6380,6 +7550,26 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Handler != null) return (true, 2, 0); + else goto case 2; + case 2: + if (Filter != null) return (true, 1, 0); + else goto case 1; + case 1: + if (ExceptionDeclarationOrExpression != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.CatchClause; @@ -6400,7 +7590,10 @@ internal SwitchCaseOperation(ImmutableArray clauses, Immut public ImmutableArray Body { get; } public ImmutableArray Locals { get; } public IOperation? Condition { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Clauses.Length + + Body.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Clauses.Length @@ -6409,7 +7602,7 @@ 1 when index < Body.Length => Body[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6430,6 +7623,27 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Body.IsEmpty) return (true, 1, Body.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (!Clauses.IsEmpty) return (true, 0, Clauses.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.SwitchCase; @@ -6450,8 +7664,10 @@ internal sealed partial class DefaultCaseClauseOperation : BaseCaseClauseOperati { internal DefaultCaseClauseOperation(ILabelSymbol? label, SemanticModel? semanticModel, SyntaxNode syntax, bool isImplicit) : base(label, semanticModel, syntax, isImplicit) { } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.CaseClause; @@ -6469,7 +7685,10 @@ internal PatternCaseClauseOperation(ILabelSymbol label, IPatternOperation patter public new ILabelSymbol Label => base.Label!; public IPatternOperation Pattern { get; } public IOperation? Guard { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Pattern is null ? 0 : 1) + + (Guard is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Pattern != null @@ -6478,7 +7697,7 @@ protected override IOperation GetCurrent(int slot, int index) => Guard, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6495,6 +7714,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Guard != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Pattern != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.CaseClause; @@ -6511,7 +7747,10 @@ internal RangeCaseClauseOperation(IOperation minimumValue, IOperation maximumVal } public IOperation MinimumValue { get; } public IOperation MaximumValue { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (MinimumValue is null ? 0 : 1) + + (MaximumValue is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when MinimumValue != null @@ -6520,7 +7759,7 @@ protected override IOperation GetCurrent(int slot, int index) => MaximumValue, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6537,6 +7776,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (MaximumValue != null) return (true, 1, 0); + else goto case 1; + case 1: + if (MinimumValue != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.CaseClause; @@ -6553,14 +7809,16 @@ internal RelationalCaseClauseOperation(IOperation value, BinaryOperatorKind rela } public IOperation Value { get; } public BinaryOperatorKind Relation { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6574,6 +7832,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.CaseClause; @@ -6588,14 +7860,16 @@ internal SingleValueCaseClauseOperation(IOperation value, ILabelSymbol? label, S Value = SetParentOperation(value, this); } public IOperation Value { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6609,6 +7883,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.CaseClause; @@ -6628,14 +7916,16 @@ internal InterpolatedStringTextOperation(IOperation text, SemanticModel? semanti Text = SetParentOperation(text, this); } public IOperation Text { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Text is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Text != null => Text, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6649,6 +7939,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Text != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.InterpolatedStringText; @@ -6667,7 +7971,11 @@ internal InterpolationOperation(IOperation expression, IOperation? alignment, IO public IOperation Expression { get; } public IOperation? Alignment { get; } public IOperation? FormatString { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Expression is null ? 0 : 1) + + (Alignment is null ? 0 : 1) + + (FormatString is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Expression != null @@ -6678,7 +7986,7 @@ protected override IOperation GetCurrent(int slot, int index) => FormatString, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6698,6 +8006,26 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (FormatString != null) return (true, 2, 0); + else goto case 2; + case 2: + if (Alignment != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Expression != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Interpolation; @@ -6723,14 +8051,16 @@ internal ConstantPatternOperation(IOperation value, ITypeSymbol inputType, IType Value = SetParentOperation(value, this); } public IOperation Value { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6744,6 +8074,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ConstantPattern; @@ -6762,8 +8106,10 @@ internal DeclarationPatternOperation(ITypeSymbol? matchedType, bool matchesNull, public ITypeSymbol? MatchedType { get; } public bool MatchesNull { get; } public ISymbol? DeclaredSymbol { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.DeclarationPattern; @@ -6783,7 +8129,10 @@ internal TupleBinaryOperation(BinaryOperatorKind operatorKind, IOperation leftOp public BinaryOperatorKind OperatorKind { get; } public IOperation LeftOperand { get; } public IOperation RightOperand { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (LeftOperand is null ? 0 : 1) + + (RightOperand is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when LeftOperand != null @@ -6792,7 +8141,7 @@ protected override IOperation GetCurrent(int slot, int index) => RightOperand, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6809,6 +8158,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (RightOperand != null) return (true, 1, 0); + else goto case 1; + case 1: + if (LeftOperand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.TupleBinary; @@ -6830,7 +8196,10 @@ internal sealed partial class MethodBodyOperation : BaseMethodBodyBaseOperation, { internal MethodBodyOperation(IBlockOperation? blockBody, IBlockOperation? expressionBody, SemanticModel? semanticModel, SyntaxNode syntax, bool isImplicit) : base(blockBody, expressionBody, semanticModel, syntax, isImplicit) { } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (BlockBody is null ? 0 : 1) + + (ExpressionBody is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when BlockBody != null @@ -6839,7 +8208,7 @@ protected override IOperation GetCurrent(int slot, int index) => ExpressionBody, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6856,6 +8225,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (ExpressionBody != null) return (true, 1, 0); + else goto case 1; + case 1: + if (BlockBody != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.MethodBody; @@ -6872,7 +8258,11 @@ internal ConstructorBodyOperation(ImmutableArray locals, IOperatio } public ImmutableArray Locals { get; } public IOperation? Initializer { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Initializer is null ? 0 : 1) + + (BlockBody is null ? 0 : 1) + + (ExpressionBody is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Initializer != null @@ -6883,7 +8273,7 @@ protected override IOperation GetCurrent(int slot, int index) => ExpressionBody, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6903,6 +8293,26 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (ExpressionBody != null) return (true, 2, 0); + else goto case 2; + case 2: + if (BlockBody != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Initializer != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ConstructorBody; @@ -6918,8 +8328,10 @@ internal DiscardOperation(IDiscardSymbol discardSymbol, SemanticModel? semanticM Type = type; } public IDiscardSymbol DiscardSymbol { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Discard; @@ -6936,14 +8348,16 @@ internal FlowCaptureOperation(CaptureId id, IOperation value, SemanticModel? sem } public CaptureId Id { get; } public IOperation Value { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -6957,6 +8371,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.FlowCapture; @@ -6975,8 +8403,10 @@ internal FlowCaptureReferenceOperation(CaptureId id, bool isInitialization, Sema } public CaptureId Id { get; } public bool IsInitialization { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.FlowCaptureReference; @@ -6993,14 +8423,16 @@ internal IsNullOperation(IOperation operand, SemanticModel? semanticModel, Synta Type = type; } public IOperation Operand { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operand is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operand != null => Operand, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7014,6 +8446,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Operand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.IsNull; @@ -7027,8 +8473,10 @@ internal CaughtExceptionOperation(SemanticModel? semanticModel, SyntaxNode synta { Type = type; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.CaughtException; @@ -7044,8 +8492,10 @@ internal StaticLocalInitializationSemaphoreOperation(ILocalSymbol local, Semanti Type = type; } public ILocalSymbol Local { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.StaticLocalInitializationSemaphore; @@ -7059,7 +8509,10 @@ internal CoalesceAssignmentOperation(IOperation target, IOperation value, Semant { Type = type; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Target is null ? 0 : 1) + + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Target != null @@ -7068,7 +8521,7 @@ protected override IOperation GetCurrent(int slot, int index) => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7085,6 +8538,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Target != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.CoalesceAssignment; @@ -7106,7 +8576,10 @@ internal RangeOperation(IOperation? leftOperand, IOperation? rightOperand, bool public IOperation? RightOperand { get; } public bool IsLifted { get; } public IMethodSymbol? Method { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (LeftOperand is null ? 0 : 1) + + (RightOperand is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when LeftOperand != null @@ -7115,7 +8588,7 @@ protected override IOperation GetCurrent(int slot, int index) => RightOperand, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7132,6 +8605,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (RightOperand != null) return (true, 1, 0); + else goto case 1; + case 1: + if (LeftOperand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.Range; @@ -7148,14 +8638,16 @@ internal ReDimOperation(ImmutableArray clauses, bool pres } public ImmutableArray Clauses { get; } public bool Preserve { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Clauses.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Clauses.Length => Clauses[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7171,6 +8663,22 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Clauses.IsEmpty) return (true, 0, Clauses.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ReDim; @@ -7187,7 +8695,10 @@ internal ReDimClauseOperation(IOperation operand, ImmutableArray dim } public IOperation Operand { get; } public ImmutableArray DimensionSizes { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operand is null ? 0 : 1) + + DimensionSizes.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operand != null @@ -7196,7 +8707,7 @@ 1 when index < DimensionSizes.Length => DimensionSizes[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7215,6 +8726,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!DimensionSizes.IsEmpty) return (true, 1, DimensionSizes.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (Operand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ReDimClause; @@ -7237,7 +8767,10 @@ internal RecursivePatternOperation(ITypeSymbol matchedType, ISymbol? deconstruct public ImmutableArray DeconstructionSubpatterns { get; } public ImmutableArray PropertySubpatterns { get; } public ISymbol? DeclaredSymbol { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + DeconstructionSubpatterns.Length + + PropertySubpatterns.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < DeconstructionSubpatterns.Length @@ -7246,7 +8779,7 @@ 1 when index < PropertySubpatterns.Length => PropertySubpatterns[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7258,11 +8791,32 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev case 0: if (!PropertySubpatterns.IsEmpty) return (true, 1, 0); else goto case 1; - case 1 when previousIndex + 1 < PropertySubpatterns.Length: - return (true, 1, previousIndex + 1); + case 1 when previousIndex + 1 < PropertySubpatterns.Length: + return (true, 1, previousIndex + 1); + case 1: + case 2: + return (false, 2, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!PropertySubpatterns.IsEmpty) return (true, 1, PropertySubpatterns.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); case 1: - case 2: - return (false, 2, 0); + if (!DeconstructionSubpatterns.IsEmpty) return (true, 0, DeconstructionSubpatterns.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); default: throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } @@ -7277,8 +8831,10 @@ internal sealed partial class DiscardPatternOperation : BasePatternOperation, ID { internal DiscardPatternOperation(ITypeSymbol inputType, ITypeSymbol narrowedType, SemanticModel? semanticModel, SyntaxNode syntax, bool isImplicit) : base(inputType, narrowedType, semanticModel, syntax, isImplicit) { } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.DiscardPattern; @@ -7298,7 +8854,10 @@ internal SwitchExpressionOperation(IOperation value, ImmutableArray Arms { get; } public bool IsExhaustive { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1) + + Arms.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null @@ -7307,7 +8866,7 @@ 1 when index < Arms.Length => Arms[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7326,6 +8885,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Arms.IsEmpty) return (true, 1, Arms.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.SwitchExpression; @@ -7346,7 +8924,11 @@ internal SwitchExpressionArmOperation(IPatternOperation pattern, IOperation? gua public IOperation? Guard { get; } public IOperation Value { get; } public ImmutableArray Locals { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Pattern is null ? 0 : 1) + + (Guard is null ? 0 : 1) + + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Pattern != null @@ -7357,7 +8939,7 @@ protected override IOperation GetCurrent(int slot, int index) => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7377,6 +8959,26 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 2, 0); + else goto case 2; + case 2: + if (Guard != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Pattern != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.SwitchExpressionArm; @@ -7393,7 +8995,10 @@ internal PropertySubpatternOperation(IOperation member, IPatternOperation patter } public IOperation Member { get; } public IPatternOperation Pattern { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Member is null ? 0 : 1) + + (Pattern is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Member != null @@ -7402,7 +9007,7 @@ protected override IOperation GetCurrent(int slot, int index) => Pattern, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7419,6 +9024,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Pattern != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Member != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.PropertySubpattern; @@ -7436,7 +9058,10 @@ internal AggregateQueryOperation(IOperation group, IOperation aggregation, Seman } public IOperation Group { get; } public IOperation Aggregation { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Group is null ? 0 : 1) + + (Aggregation is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Group != null @@ -7445,7 +9070,7 @@ protected override IOperation GetCurrent(int slot, int index) => Aggregation, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7462,6 +9087,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Aggregation != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Group != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.None; @@ -7480,7 +9122,10 @@ internal FixedOperation(ImmutableArray locals, IVariableDeclaratio public ImmutableArray Locals { get; } public IVariableDeclarationGroupOperation Variables { get; } public IOperation Body { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Variables is null ? 0 : 1) + + (Body is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Variables != null @@ -7489,7 +9134,7 @@ protected override IOperation GetCurrent(int slot, int index) => Body, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7506,6 +9151,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Body != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Variables != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.None; @@ -7521,14 +9183,16 @@ internal NoPiaObjectCreationOperation(IObjectOrCollectionInitializerOperation? i Type = type; } public IObjectOrCollectionInitializerOperation? Initializer { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Initializer is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Initializer != null => Initializer, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7542,6 +9206,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Initializer != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.None; @@ -7557,8 +9235,10 @@ internal PlaceholderOperation(PlaceholderKind placeholderKind, SemanticModel? se Type = type; } public PlaceholderKind PlaceholderKind { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.None; @@ -7575,7 +9255,10 @@ internal WithStatementOperation(IOperation body, IOperation value, SemanticModel } public IOperation Body { get; } public IOperation Value { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Body is null ? 0 : 1) + + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null @@ -7584,7 +9267,7 @@ protected override IOperation GetCurrent(int slot, int index) => Body, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7601,6 +9284,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Body != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.None; @@ -7619,14 +9319,16 @@ internal UsingDeclarationOperation(IVariableDeclarationGroupOperation declaratio public IVariableDeclarationGroupOperation DeclarationGroup { get; } public bool IsAsynchronous { get; } public DisposeOperationInfo DisposeInfo { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (DeclarationGroup is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when DeclarationGroup != null => DeclarationGroup, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7640,6 +9342,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (DeclarationGroup != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.UsingDeclaration; @@ -7654,14 +9370,16 @@ internal NegatedPatternOperation(IPatternOperation pattern, ITypeSymbol inputTyp Pattern = SetParentOperation(pattern, this); } public IPatternOperation Pattern { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Pattern is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Pattern != null => Pattern, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7675,6 +9393,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Pattern != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.NegatedPattern; @@ -7693,7 +9425,10 @@ internal BinaryPatternOperation(BinaryOperatorKind operatorKind, IPatternOperati public BinaryOperatorKind OperatorKind { get; } public IPatternOperation LeftPattern { get; } public IPatternOperation RightPattern { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (LeftPattern is null ? 0 : 1) + + (RightPattern is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when LeftPattern != null @@ -7702,7 +9437,7 @@ protected override IOperation GetCurrent(int slot, int index) => RightPattern, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7719,6 +9454,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (RightPattern != null) return (true, 1, 0); + else goto case 1; + case 1: + if (LeftPattern != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.BinaryPattern; @@ -7733,8 +9485,10 @@ internal TypePatternOperation(ITypeSymbol matchedType, ITypeSymbol inputType, IT MatchedType = matchedType; } public ITypeSymbol MatchedType { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.TypePattern; @@ -7751,14 +9505,16 @@ internal RelationalPatternOperation(BinaryOperatorKind operatorKind, IOperation } public BinaryOperatorKind OperatorKind { get; } public IOperation Value { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Value is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Value != null => Value, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7772,6 +9528,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Value != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.RelationalPattern; @@ -7791,7 +9561,10 @@ internal WithOperation(IOperation operand, IMethodSymbol? cloneMethod, IObjectOr public IOperation Operand { get; } public IMethodSymbol? CloneMethod { get; } public IObjectOrCollectionInitializerOperation Initializer { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Operand is null ? 0 : 1) + + (Initializer is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operand != null @@ -7800,7 +9573,7 @@ protected override IOperation GetCurrent(int slot, int index) => Initializer, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7817,6 +9590,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Initializer != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Operand != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.With; @@ -7838,7 +9628,10 @@ internal InterpolatedStringHandlerCreationOperation(IOperation handlerCreation, public bool HandlerCreationHasSuccessParameter { get; } public bool HandlerAppendCallsReturnBool { get; } public IOperation Content { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (HandlerCreation is null ? 0 : 1) + + (Content is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when HandlerCreation != null @@ -7847,7 +9640,7 @@ protected override IOperation GetCurrent(int slot, int index) => Content, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7864,6 +9657,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Content != null) return (true, 1, 0); + else goto case 1; + case 1: + if (HandlerCreation != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.InterpolatedStringHandlerCreation; @@ -7880,7 +9690,10 @@ internal InterpolatedStringAdditionOperation(IOperation left, IOperation right, } public IOperation Left { get; } public IOperation Right { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Left is null ? 0 : 1) + + (Right is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Left != null @@ -7889,7 +9702,7 @@ protected override IOperation GetCurrent(int slot, int index) => Right, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7906,6 +9719,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Right != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Left != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.InterpolatedStringAddition; @@ -7921,14 +9751,16 @@ internal InterpolatedStringAppendOperation(IOperation appendCall, OperationKind Kind = kind; } public IOperation AppendCall { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (AppendCall is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when AppendCall != null => AppendCall, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -7942,6 +9774,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (AppendCall != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind { get; } @@ -7958,8 +9804,10 @@ internal InterpolatedStringHandlerArgumentPlaceholderOperation(int argumentIndex } public int ArgumentIndex { get; } public InterpolatedStringArgumentPlaceholderKind PlaceholderKind { get; } - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override int ChildOperationsCount => 0; + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.InterpolatedStringHandlerArgumentPlaceholder; @@ -7977,7 +9825,10 @@ internal FunctionPointerInvocationOperation(IOperation target, ImmutableArray Arguments { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Target is null ? 0 : 1) + + Arguments.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Target != null @@ -7986,7 +9837,7 @@ 1 when index < Arguments.Length => Arguments[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -8005,6 +9856,25 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Arguments.IsEmpty) return (true, 1, Arguments.Length - 1); + else goto case 1; + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + case 1: + if (Target != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.FunctionPointerInvocation; @@ -8025,14 +9895,16 @@ internal ListPatternOperation(ISymbol? lengthSymbol, ISymbol? indexerSymbol, Imm public ISymbol? IndexerSymbol { get; } public ImmutableArray Patterns { get; } public ISymbol? DeclaredSymbol { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + Patterns.Length; + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Patterns.Length => Patterns[index], _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -8048,6 +9920,22 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Patterns.IsEmpty) return (true, 0, Patterns.Length - 1); + else goto case 0; + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ListPattern; @@ -8064,14 +9952,16 @@ internal SlicePatternOperation(ISymbol? sliceSymbol, IPatternOperation? pattern, } public ISymbol? SliceSymbol { get; } public IPatternOperation? Pattern { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Pattern is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Pattern != null => Pattern, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -8085,6 +9975,20 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Pattern != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.SlicePattern; @@ -8106,7 +10010,10 @@ internal ImplicitIndexerReferenceOperation(IOperation instance, IOperation argum public IOperation Argument { get; } public ISymbol LengthSymbol { get; } public ISymbol IndexerSymbol { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => + (Instance is null ? 0 : 1) + + (Argument is null ? 0 : 1); + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Instance != null @@ -8115,7 +10022,7 @@ protected override IOperation GetCurrent(int slot, int index) => Argument, _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -8132,6 +10039,23 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Argument != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Instance != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.ImplicitIndexerReference; diff --git a/src/Compilers/Core/Portable/InternalUtilities/ExceptionUtilities.cs b/src/Compilers/Core/Portable/InternalUtilities/ExceptionUtilities.cs index 8e3dc303ca8f3..ba9629189ff06 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/ExceptionUtilities.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/ExceptionUtilities.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; +using System.Threading; namespace Roslyn.Utilities { @@ -27,5 +28,14 @@ internal static Exception Unreachable { get { return new InvalidOperationException("This program location is thought to be unreachable."); } } + + /// + /// Determine if an exception was an , and that the provided token caused the cancellation. + /// + /// The exception to test. + /// Checked to see if the provided token was cancelled. + /// if the exception was an and the token was canceled. + internal static bool IsCurrentOperationBeingCancelled(Exception exception, CancellationToken cancellationToken) + => exception is OperationCanceledException && cancellationToken.IsCancellationRequested; } } diff --git a/src/Compilers/Core/Portable/InternalUtilities/FailFast.cs b/src/Compilers/Core/Portable/InternalUtilities/FailFast.cs index 3260ed46f5beb..b53cf5cea8948 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/FailFast.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/FailFast.cs @@ -20,9 +20,7 @@ internal static class FailFast [DebuggerHidden] [DoesNotReturn] -#if !NETSTANDARD1_3 [MethodImpl(MethodImplOptions.Synchronized)] -#endif internal static void OnFatalException(Exception exception) { // EDMAURER Now using the managed API to fail fast so as to default @@ -49,9 +47,7 @@ internal static void OnFatalException(Exception exception) [DebuggerHidden] [DoesNotReturn] -#if !NETSTANDARD1_3 [MethodImpl(MethodImplOptions.Synchronized)] -#endif internal static void Fail(string message) { DumpStackTrace(message: message); @@ -82,7 +78,7 @@ internal static void DumpStackTrace(Exception? exception = null, string? message } } -#if !NET20 && !NETSTANDARD1_3 +#if !NET20 Console.WriteLine("Stack trace of handler"); var stackTrace = new StackTrace(); Console.WriteLine(stackTrace.ToString()); diff --git a/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs b/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs index 6007023687490..af766990930ed 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Threading; +using Roslyn.Utilities; #if NET20 // Some APIs referenced by documentation comments are not available on .NET Framework 2.0. @@ -46,8 +47,6 @@ public static ErrorReporterHandler? Handler } } - public static bool HandlerIsNonFatal { get; set; } - /// /// Same as setting the Handler property except that it avoids the assert. This is useful in /// test code which needs to verify the handler is called in specific cases and will continually @@ -61,7 +60,7 @@ public static void OverwriteHandler(ErrorReporterHandler? value) // In the result provider, we aren't copying our handler to somewhere else, so we don't // need this method. It's too much of a challenge to shared code to work in // old versions of the runtime since APIs changed over time. -#if !NET20 && !NETSTANDARD1_3 +#if !NET20 /// /// Copies the handler in this instance to the linked copy of this type in this other assembly. @@ -84,16 +83,10 @@ public static void CopyHandlerTo(Assembly assembly) { targetHandlerProperty.SetValue(obj: null, value: null); } - - var targetIsNonFatalProperty = targetType.GetProperty(nameof(HandlerIsNonFatal), BindingFlags.Static | BindingFlags.Public)!; - targetIsNonFatalProperty.SetValue(obj: null, value: HandlerIsNonFatal); } #endif - private static bool IsCurrentOperationBeingCancelled(Exception exception, CancellationToken cancellationToken) - => exception is OperationCanceledException && cancellationToken.IsCancellationRequested; - /// /// Use in an exception filter to report an error without catching the exception. /// The error is reported by calling . @@ -143,7 +136,7 @@ public static bool ReportAndPropagateUnlessCanceled(Exception exception, ErrorSe [DebuggerHidden] public static bool ReportAndPropagateUnlessCanceled(Exception exception, CancellationToken contextCancellationToken, ErrorSeverity severity = ErrorSeverity.Uncategorized) { - if (IsCurrentOperationBeingCancelled(exception, contextCancellationToken)) + if (ExceptionUtilities.IsCurrentOperationBeingCancelled(exception, contextCancellationToken)) { return false; } @@ -151,6 +144,11 @@ public static bool ReportAndPropagateUnlessCanceled(Exception exception, Cancell return ReportAndPropagate(exception, severity); } + // Since the command line compiler has no way to catch exceptions, report them, and march on, we + // simply don't offer such a mechanism here to avoid accidental swallowing of exceptions. + +#if !COMPILERCORE + /// /// Report an error. /// Calls and doesn't pass the exception through (the method returns true). @@ -162,24 +160,14 @@ public static bool ReportAndPropagateUnlessCanceled(Exception exception, Cancell /// /// True to catch the exception. [DebuggerHidden] -#if COMPILERCORE - private -#else - public -#endif - static bool ReportAndCatch(Exception exception, ErrorSeverity severity = ErrorSeverity.Uncategorized) + public static bool ReportAndCatch(Exception exception, ErrorSeverity severity = ErrorSeverity.Uncategorized) { Report(exception, severity); return true; } [DebuggerHidden] -#if COMPILERCORE - private -#else - public -#endif - static bool ReportWithDumpAndCatch(Exception exception, ErrorSeverity severity = ErrorSeverity.Uncategorized) + public static bool ReportWithDumpAndCatch(Exception exception, ErrorSeverity severity = ErrorSeverity.Uncategorized) { Report(exception, severity, forceDump: true); return true; @@ -192,42 +180,13 @@ static bool ReportWithDumpAndCatch(Exception exception, ErrorSeverity severity = /// to catch the exception if the error was reported; otherwise, /// to propagate the exception if the operation was cancelled. [DebuggerHidden] -#if COMPILERCORE - private -#else - public -#endif - static bool ReportAndCatchUnlessCanceled(Exception exception, ErrorSeverity severity = ErrorSeverity.Uncategorized) - { - if (exception is OperationCanceledException) - { - return false; - } - - return ReportAndCatch(exception, severity); - } - - /// - /// Use in an exception filter to report an error (by calling ) and catch - /// the exception, unless the operation was cancelled. - /// - /// to catch the exception if the error was reported; otherwise, - /// to propagate the exception if the operation was cancelled. - // This is only a temporary shim; the removal is tracked by https://github.com/dotnet/roslyn/issues/58375. - [DebuggerHidden] - [Obsolete("This is only to support places the compiler is catching exceptions on the command line; do not use in new code.")] - public static bool ReportIfNonFatalAndCatchUnlessCanceled(Exception exception, ErrorSeverity severity = ErrorSeverity.Uncategorized) + public static bool ReportAndCatchUnlessCanceled(Exception exception, ErrorSeverity severity = ErrorSeverity.Uncategorized) { if (exception is OperationCanceledException) { return false; } - if (!HandlerIsNonFatal) - { - return true; - } - return ReportAndCatch(exception, severity); } @@ -251,14 +210,9 @@ public static bool ReportIfNonFatalAndCatchUnlessCanceled(Exception exception, E /// to catch the exception if the error was reported; otherwise, /// to propagate the exception if the operation was cancelled. [DebuggerHidden] -#if COMPILERCORE - private -#else - public -#endif - static bool ReportAndCatchUnlessCanceled(Exception exception, CancellationToken contextCancellationToken, ErrorSeverity severity = ErrorSeverity.Uncategorized) + public static bool ReportAndCatchUnlessCanceled(Exception exception, CancellationToken contextCancellationToken, ErrorSeverity severity = ErrorSeverity.Uncategorized) { - if (IsCurrentOperationBeingCancelled(exception, contextCancellationToken)) + if (ExceptionUtilities.IsCurrentOperationBeingCancelled(exception, contextCancellationToken)) { return false; } @@ -266,43 +220,7 @@ static bool ReportAndCatchUnlessCanceled(Exception exception, CancellationToken return ReportAndCatch(exception, severity); } - /// - /// Use in an exception filter to report an error (by calling ) and - /// catch the exception, unless the operation was cancelled at the request of - /// . - /// - /// Cancellable operations are only expected to throw if the - /// applicable indicates cancellation is requested by setting - /// . Unexpected cancellation, i.e. an - /// which occurs without - /// requesting cancellation, is treated as an error by this method. - /// - /// This method does not require to match - /// , provided cancellation is expected per the previous - /// paragraph. - /// - /// A which will have - /// set if cancellation is expected. - /// to catch the exception if the error was reported; otherwise, - /// to propagate the exception if the operation was cancelled. - // This is only a temporary shim; the removal is tracked by https://github.com/dotnet/roslyn/issues/58375. - [DebuggerHidden] - [Obsolete("This is only to support places the compiler is catching and swallowing exceptions on the command line; do not use in new code.")] - public static bool ReportIfNonFatalAndCatchUnlessCanceled(Exception exception, CancellationToken contextCancellationToken, ErrorSeverity severity = ErrorSeverity.Uncategorized) - { - if (IsCurrentOperationBeingCancelled(exception, contextCancellationToken)) - { - return false; - } - - if (!HandlerIsNonFatal) - { - // We'll catch the exception, but we won't report anything. - return true; - } - - return ReportAndCatch(exception, severity); - } +#endif private static readonly object s_reportedMarker = new(); diff --git a/src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerArgumentAttribute.cs b/src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerArgumentAttribute.cs new file mode 100644 index 0000000000000..523fcfaa29300 --- /dev/null +++ b/src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerArgumentAttribute.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. + + +#if !NET6_0_OR_GREATER + +namespace System.Runtime.CompilerServices +{ + /// Indicates which arguments to a method involving an interpolated string handler should be passed to that handler. + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute + { + /// Initializes a new instance of the class. + /// The name of the argument that should be passed to the handler. + /// may be used as the name of the receiver in an instance method. + public InterpolatedStringHandlerArgumentAttribute(string argument) => Arguments = new string[] { argument }; + /// Initializes a new instance of the class. + /// The names of the arguments that should be passed to the handler. + /// may be used as the name of the receiver in an instance method. + public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) => Arguments = arguments; + /// Gets the names of the arguments that should be passed to the handler. + /// may be used as the name of the receiver in an instance method. + public string[] Arguments { get; } + } +} + +#endif diff --git a/src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerAttribute.cs b/src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerAttribute.cs new file mode 100644 index 0000000000000..f401f0728a03a --- /dev/null +++ b/src/Compilers/Core/Portable/InternalUtilities/InterpolatedStringHandlerAttribute.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#if !NET6_0_OR_GREATER + +namespace System.Runtime.CompilerServices +{ + /// Indicates the attributed type is to be used as an interpolated string handler. + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] + internal sealed class InterpolatedStringHandlerAttribute : Attribute + { + /// Initializes the . + public InterpolatedStringHandlerAttribute() { } + } +} + +#endif diff --git a/src/Compilers/Core/Portable/InternalUtilities/JsonWriter.cs b/src/Compilers/Core/Portable/InternalUtilities/JsonWriter.cs index d857dfaf9a0f9..cc08106c42b11 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/JsonWriter.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/JsonWriter.cs @@ -88,18 +88,69 @@ public void Write(string key, int value) Write(value); } + public void Write(string key, int? value) + { + WriteKey(key); + Write(value); + } + public void Write(string key, bool value) { WriteKey(key); Write(value); } + public void Write(string key, bool? value) + { + WriteKey(key); + Write(value); + } + + public void Write(string key, T value) where T : struct, Enum + { + WriteKey(key); + Write(value.ToString()); + } + + public void WriteInvariant(T value) + where T : struct, IFormattable + { + Write(value.ToString(null, CultureInfo.InvariantCulture)); + } + + public void WriteInvariant(string key, T value) + where T : struct, IFormattable + { + WriteKey(key); + WriteInvariant(value); + } + + public void WriteNull(string key) + { + WriteKey(key); + WriteNull(); + } + + public void WriteNull() + { + WritePending(); + _output.Write("null"); + _pending = Pending.CommaNewLineAndIndent; + } + public void Write(string? value) { WritePending(); - _output.Write('"'); - _output.Write(EscapeString(value)); - _output.Write('"'); + if (value is null) + { + _output.Write("null"); + } + else + { + _output.Write('"'); + _output.Write(EscapeString(value)); + _output.Write('"'); + } _pending = Pending.CommaNewLineAndIndent; } @@ -110,6 +161,18 @@ public void Write(int value) _pending = Pending.CommaNewLineAndIndent; } + public void Write(int? value) + { + if (value is { } i) + { + Write(i); + } + else + { + WriteNull(); + } + } + public void Write(bool value) { WritePending(); @@ -117,6 +180,35 @@ public void Write(bool value) _pending = Pending.CommaNewLineAndIndent; } + public void Write(bool? value) + { + if (value is { } b) + { + Write(b); + } + else + { + WriteNull(); + } + } + + public void Write(T value) where T : struct, Enum + { + Write(value.ToString()); + } + + public void Write(T? value) where T : struct, Enum + { + if (value is { } e) + { + Write(e); + } + else + { + WriteNull(); + } + } + private void WritePending() { if (_pending == Pending.None) @@ -165,7 +257,7 @@ public void Dispose() // // https://github.com/dotnet/corefx/blob/main/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JavaScriptString.cs // - private static string EscapeString(string? value) + internal static string EscapeString(string value) { PooledStringBuilder? pooledBuilder = null; StringBuilder? b = null; diff --git a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj index 2e8b0ce4a4915..4bdef9c9b6641 100644 --- a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj +++ b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj @@ -7,7 +7,6 @@ true netcoreapp3.1;netstandard2.0 $(DefineConstants);COMPILERCORE - ..\CodeAnalysisRules.ruleset true full true @@ -99,9 +98,6 @@ - - Designer - Designer diff --git a/src/Compilers/Core/Portable/Operations/ControlFlowGraph.cs b/src/Compilers/Core/Portable/Operations/ControlFlowGraph.cs index 0401307413e92..87468b40d3183 100644 --- a/src/Compilers/Core/Portable/Operations/ControlFlowGraph.cs +++ b/src/Compilers/Core/Portable/Operations/ControlFlowGraph.cs @@ -178,21 +178,9 @@ internal static ControlFlowGraph CreateCore(IOperation operation, string argumen throw new ArgumentException(CodeAnalysisResources.OperationHasNullSemanticModel, argumentNameForException); } - try - { - ControlFlowGraph controlFlowGraph = ControlFlowGraphBuilder.Create(operation); - Debug.Assert(controlFlowGraph.OriginalOperation == operation); - return controlFlowGraph; - } -#pragma warning disable CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete; tracked by https://github.com/dotnet/roslyn/issues/58375 - catch (Exception e) when (FatalError.ReportIfNonFatalAndCatchUnlessCanceled(e, cancellationToken)) -#pragma warning restore CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete - { - // Log a Non-fatal-watson and then ignore the crash in the attempt of getting flow graph. - Debug.Assert(false, "\n" + e.ToString()); - } - - return null; + ControlFlowGraph controlFlowGraph = ControlFlowGraphBuilder.Create(operation); + Debug.Assert(controlFlowGraph.OriginalOperation == operation); + return controlFlowGraph; } /// diff --git a/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs b/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs index 9911d367df9bd..ff24f9434ca13 100644 --- a/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs +++ b/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs @@ -127,7 +127,6 @@ public static ControlFlowGraph Create(IOperation body, ControlFlowGraph? parent case OperationKind.AnonymousFunction: Debug.Assert(captureIdDispenser != null); var anonymousFunction = (IAnonymousFunctionOperation)body; - builder.VisitNullChecks(anonymousFunction, anonymousFunction.Symbol.Parameters); builder.VisitStatement(anonymousFunction.Body); break; default: @@ -1481,12 +1480,6 @@ bool visitPossibleUsingDeclarationInLabel(ILabeledOperation labelOperation) EnterRegion(new RegionBuilder(ControlFlowRegionKind.LocalLifetime, locals: operation.Locals)); - // https://github.com/dotnet/roslyn/issues/58335: this implementation doesn't handle record primary constructors - if (operation.SemanticModel!.GetDeclaredSymbol(operation.Syntax) is IMethodSymbol method) - { - VisitNullChecks(operation, method.Parameters); - } - if (operation.Initializer != null) { VisitStatement(operation.Initializer); @@ -1501,157 +1494,11 @@ bool visitPossibleUsingDeclarationInLabel(ILabeledOperation labelOperation) public override IOperation? VisitMethodBodyOperation(IMethodBodyOperation operation, int? captureIdForResult) { StartVisitingStatement(operation); - - // https://github.com/dotnet/roslyn/issues/58335: do we need to use SemanticModel here? - var member = operation.SemanticModel!.GetDeclaredSymbol(operation.Syntax); Debug.Assert(captureIdForResult is null); - VisitNullChecks(operation, ((IMethodSymbol)member!).Parameters); - VisitMethodBodyBaseOperation(operation); return FinishVisitingStatement(operation); } - private void VisitNullChecks(IOperation operation, ImmutableArray parameters) - { - var temp = _currentStatement; - foreach (var param in parameters) - { - if (param.IsNullChecked) - { - // https://github.com/dotnet/roslyn/issues/58335: do we need to use SemanticModel here? - var check = GenerateNullCheckForParameter(param, operation.Syntax, ((Operation)operation).OwningSemanticModel!); - _currentStatement = check; - VisitConditional(check, captureIdForResult: null); - } - } - _currentStatement = temp; - } - - private ConditionalOperation GenerateNullCheckForParameter(IParameterSymbol parameter, SyntaxNode syntax, SemanticModel semanticModel) - { - Debug.Assert(parameter.Language == LanguageNames.CSharp); - var paramReference = new ParameterReferenceOperation(parameter, semanticModel, syntax, parameter.Type, isImplicit: true); - var boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); - - IOperation conditionOp; - if (ITypeSymbolHelpers.IsNullableType(parameter.Type)) - { - // https://github.com/dotnet/roslyn/issues/58335: is there a better way to get the HasValue symbol here? - // This way doesn't work with compilation.MakeMemberMissing for testing - var nullableHasValueProperty = parameter.Type.GetMembers(nameof(Nullable.HasValue)).FirstOrDefault() as IPropertySymbol; - var nullableHasValueGet = nullableHasValueProperty?.GetMethod; - if (nullableHasValueGet is null) - { - conditionOp = new UnaryOperation( - UnaryOperatorKind.Not, - new InvalidOperation( - ImmutableArray.Create(paramReference), - semanticModel, - syntax, - boolType, - constantValue: null, - isImplicit: true), - isLifted: false, - isChecked: false, - operatorMethod: null, - semanticModel, - syntax, - boolType, - constantValue: null, - isImplicit: true); - } - else - { - conditionOp = new UnaryOperation( - UnaryOperatorKind.Not, - new InvocationOperation( - targetMethod: nullableHasValueGet, - instance: paramReference, - isVirtual: false, - arguments: ImmutableArray.Empty, - semanticModel, - syntax, - boolType, - isImplicit: true), - isLifted: false, - isChecked: false, - operatorMethod: null, - semanticModel, - syntax, - boolType, - constantValue: null, - isImplicit: true); - } - } - else - { - conditionOp = new BinaryOperation( - BinaryOperatorKind.Equals, - paramReference, - new LiteralOperation(semanticModel, syntax, parameter.Type, ConstantValue.Null, isImplicit: true), - isLifted: false, - isChecked: false, - isCompareText: false, - operatorMethod: null, - unaryOperatorMethod: null, - semanticModel, - syntax, - boolType, - constantValue: null, - isImplicit: true); - } - - var paramNameLiteral = new LiteralOperation(semanticModel, syntax, _compilation.GetSpecialType(SpecialType.System_String), ConstantValue.Create(parameter.Name), isImplicit: true); - var argumentNullExceptionMethod = (IMethodSymbol?)_compilation.CommonGetWellKnownTypeMember(WellKnownMember.System_ArgumentNullException__ctorString)?.GetISymbol(); - var argumentNullExceptionType = argumentNullExceptionMethod?.ContainingType; - - // Occurs when a member is missing. - IOperation argumentNullExceptionObject; - if (argumentNullExceptionMethod is null) - { - argumentNullExceptionObject = new InvalidOperation( - children: ImmutableArray.Create((IOperation)paramNameLiteral), - semanticModel, - syntax, - argumentNullExceptionType, - constantValue: null, - isImplicit: true); - } - else - { - argumentNullExceptionObject = new ObjectCreationOperation( - argumentNullExceptionMethod, - initializer: null, - ImmutableArray.Create( - new ArgumentOperation( - ArgumentKind.Explicit, - parameter: argumentNullExceptionMethod.Parameters[0], - value: paramNameLiteral, - OperationFactory.IdentityConversion, - OperationFactory.IdentityConversion, - semanticModel, - syntax, - isImplicit: true)), - semanticModel, - syntax, - argumentNullExceptionType, - constantValue: null, - isImplicit: true); - } - - IOperation whenTrue = new ExpressionStatementOperation( - new ThrowOperation( - argumentNullExceptionObject, - semanticModel, - syntax, - argumentNullExceptionType, - isImplicit: true), - semanticModel, - syntax, - isImplicit: true); - return new ConditionalOperation(conditionOp, whenTrue, whenFalse: null, isRef: false, semanticModel, syntax, boolType, constantValue: null, isImplicit: true); - } - private void VisitMethodBodyBaseOperation(IMethodBodyBaseOperation operation) { Debug.Assert(_currentStatement == operation); @@ -1764,7 +1611,7 @@ private void VisitMethodBodies(IBlockOperation? blockBody, IBlockOperation? expr { IOperation? rewrittenThrow = base.Visit(whenTrueConversion.Operand, null); Debug.Assert(rewrittenThrow!.Kind == OperationKind.None); - Debug.Assert(rewrittenThrow.Children.IsEmpty()); + Debug.Assert(rewrittenThrow.ChildOperations.IsEmpty()); UnconditionalBranch(afterIf); @@ -1782,7 +1629,7 @@ private void VisitMethodBodies(IBlockOperation? blockBody, IBlockOperation? expr IOperation rewrittenThrow = BaseVisitRequired(whenFalseConversion.Operand, null); Debug.Assert(rewrittenThrow.Kind == OperationKind.None); - Debug.Assert(rewrittenThrow.Children.IsEmpty()); + Debug.Assert(rewrittenThrow.ChildOperations.IsEmpty()); } else { @@ -2984,7 +2831,7 @@ private void VisitConditionalBranchCore(IOperation condition, [NotNull] ref Basi IOperation? rewrittenThrow = base.Visit(conversion.Operand, null); Debug.Assert(rewrittenThrow != null); Debug.Assert(rewrittenThrow.Kind == OperationKind.None); - Debug.Assert(rewrittenThrow.Children.IsEmpty()); + Debug.Assert(rewrittenThrow.ChildOperations.IsEmpty()); dest = dest ?? new BasicBlockBuilder(BasicBlockKind.Block); return; } @@ -3115,7 +2962,7 @@ public override IOperation VisitCoalesce(ICoalesceOperation operation, int? capt IOperation? rewrittenThrow = base.Visit(conversion.Operand, null); Debug.Assert(rewrittenThrow != null); Debug.Assert(rewrittenThrow.Kind == OperationKind.None); - Debug.Assert(rewrittenThrow.Children.IsEmpty()); + Debug.Assert(rewrittenThrow.ChildOperations.IsEmpty()); } else { @@ -6305,7 +6152,6 @@ IOperation visitAndCaptureInitializer(IPropertySymbol initializedProperty, IOper private IOperation? VisitLocalFunctionAsRoot(ILocalFunctionOperation operation) { Debug.Assert(_currentStatement == null); - VisitNullChecks(operation, operation.Symbol.Parameters); VisitMethodBodies(operation.Body, operation.IgnoredBody); return null; } diff --git a/src/Compilers/Core/Portable/Operations/IOperation.OperationList.Reversed.cs b/src/Compilers/Core/Portable/Operations/IOperation.OperationList.Reversed.cs new file mode 100644 index 0000000000000..2f8b0d32ff638 --- /dev/null +++ b/src/Compilers/Core/Portable/Operations/IOperation.OperationList.Reversed.cs @@ -0,0 +1,142 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis +{ + public partial interface IOperation + { + public readonly partial struct OperationList + { + /// + /// Implements a reverse-order struct-based collection of nodes. + /// This collection is ordered, but random access into the collection is not provided. + /// + [NonDefaultable] + public readonly struct Reversed : IReadOnlyCollection + { + private readonly Operation _operation; + + internal Reversed(Operation operation) + { + _operation = operation; + } + + public int Count => _operation.ChildOperationsCount; + + public Enumerator GetEnumerator() => new Enumerator(_operation); + + public ImmutableArray ToImmutableArray() + { + Enumerator enumerator = GetEnumerator(); + switch (_operation) + { + case { ChildOperationsCount: 0 }: + return ImmutableArray.Empty; + case NoneOperation { Children: var children }: + return reverseArray(children); + case InvalidOperation { Children: var children }: + return reverseArray(children); + default: + var builder = ArrayBuilder.GetInstance(Count); + foreach (var child in this) + { + builder.Add(child); + } + return builder.ToImmutableAndFree(); + } + + static ImmutableArray reverseArray(ImmutableArray input) + { + var builder = ArrayBuilder.GetInstance(input.Length); + for (int i = input.Length - 1; i >= 0; i--) + { + builder.Add(input[i]); + } + + return builder.ToImmutableAndFree(); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + if (this.Count == 0) + { + return SpecializedCollections.EmptyEnumerator(); + } + + return new EnumeratorImpl(new Enumerator(_operation)); + } + + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); + + /// + /// Implements a reverse-order struct-based enumerator for nodes. This type is not hardened + /// to default(Enumerator), and will null reference in these cases. Calling after + /// has returned false will throw an . + /// + [NonDefaultable] + public struct Enumerator + { + private readonly Operation _operation; + private int _currentSlot; + private int _currentIndex; + + internal Enumerator(Operation operation) + { + _operation = operation; + _currentSlot = int.MaxValue; + _currentIndex = int.MaxValue; + } + + public IOperation Current + { + get + { + Debug.Assert(_operation != null && _currentSlot is >= 0 and not int.MaxValue && _currentIndex is >= 0 and not int.MaxValue); + return _operation.GetCurrent(_currentSlot, _currentIndex); + } + } + + public bool MoveNext() + { + Debug.Assert((_currentSlot == int.MaxValue) == (_currentIndex == int.MaxValue)); + (var result, _currentSlot, _currentIndex) = _operation.MoveNextReversed(_currentSlot, _currentIndex); + return result; + } + + public void Reset() + { + _currentIndex = int.MaxValue; + _currentSlot = int.MaxValue; + } + } + + private sealed class EnumeratorImpl : IEnumerator + { + private Enumerator _enumerator; + + public EnumeratorImpl(Enumerator enumerator) + { + _enumerator = enumerator; + } + + public IOperation Current => _enumerator.Current; + object? IEnumerator.Current => _enumerator.Current; + public void Dispose() { } + public bool MoveNext() => _enumerator.MoveNext(); + public void Reset() => _enumerator.Reset(); + } + } + } + } +} diff --git a/src/Compilers/Core/Portable/Operations/IOperation.OperationList.cs b/src/Compilers/Core/Portable/Operations/IOperation.OperationList.cs new file mode 100644 index 0000000000000..b1437b0cd1f58 --- /dev/null +++ b/src/Compilers/Core/Portable/Operations/IOperation.OperationList.cs @@ -0,0 +1,161 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis +{ + public partial interface IOperation + { + /// + /// Implements a struct-based collection of nodes. This collection is ordered, but + /// random access into the collection is not provided. + /// + [NonDefaultable] + public readonly partial struct OperationList : IReadOnlyCollection + { + private readonly Operation _operation; + + internal OperationList(Operation operation) + { + _operation = operation; + } + + public int Count => _operation.ChildOperationsCount; + + public Enumerator GetEnumerator() => new Enumerator(_operation); + + public ImmutableArray ToImmutableArray() + { + switch (_operation) + { + case { ChildOperationsCount: 0 }: + return ImmutableArray.Empty; + case NoneOperation { Children: var children }: + return children; + case InvalidOperation { Children: var children }: + return children; + default: + var builder = ArrayBuilder.GetInstance(Count); + foreach (var child in this) + { + builder.Add(child); + } + return builder.ToImmutableAndFree(); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + if (this.Count == 0) + { + return SpecializedCollections.EmptyEnumerator(); + } + + return new EnumeratorImpl(new Enumerator(_operation)); + } + + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); + + public bool Any() => Count > 0; + + public IOperation First() + { + var enumerator = GetEnumerator(); + if (enumerator.MoveNext()) + { + return enumerator.Current; + } + + throw new InvalidOperationException(); + } + + public Reversed Reverse() => new Reversed(_operation); + + public IOperation Last() + { + var enumerator = Reverse().GetEnumerator(); + if (enumerator.MoveNext()) + { + return enumerator.Current; + } + + throw new InvalidOperationException(); + } + + /// + /// Implements a struct-based enumerator for nodes. This type is not hardened + /// to default(Enumerator), and will null reference in these cases. Calling after + /// has returned false will throw an . + /// + [NonDefaultable] + public struct Enumerator + { + /// + /// Implementation of the and + /// members are delegated to the virtual and + /// methods, respectively. + /// + private readonly Operation _operation; + /// + /// + /// + private int _currentSlot; + private int _currentIndex; + + internal Enumerator(Operation operation) + { + _operation = operation; + _currentSlot = -1; + _currentIndex = -1; + } + + public IOperation Current + { + get + { + Debug.Assert(_operation != null && _currentSlot >= 0 && _currentIndex >= 0); + return _operation.GetCurrent(_currentSlot, _currentIndex); + } + } + + public bool MoveNext() + { + bool result; + (result, _currentSlot, _currentIndex) = _operation.MoveNext(_currentSlot, _currentIndex); + return result; + } + + public void Reset() + { + _currentSlot = -1; + _currentIndex = -1; + } + } + + private sealed class EnumeratorImpl : IEnumerator + { + private Enumerator _enumerator; + + public EnumeratorImpl(Enumerator enumerator) + { + _enumerator = enumerator; + } + + public IOperation Current => _enumerator.Current; + object? IEnumerator.Current => _enumerator.Current; + public void Dispose() { } + public bool MoveNext() => _enumerator.MoveNext(); + public void Reset() => _enumerator.Reset(); + } + } + } +} diff --git a/src/Compilers/Core/Portable/Operations/IOperation.cs b/src/Compilers/Core/Portable/Operations/IOperation.cs index 612febf7fadca..2e8ce5ac3bdee 100644 --- a/src/Compilers/Core/Portable/Operations/IOperation.cs +++ b/src/Compilers/Core/Portable/Operations/IOperation.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.Operations; @@ -16,7 +17,7 @@ namespace Microsoft.CodeAnalysis /// change it in the future. /// [InternalImplementationOnly] - public interface IOperation + public partial interface IOperation { /// /// IOperation that has this operation as a child. Null for the root. @@ -44,10 +45,16 @@ public interface IOperation Optional ConstantValue { get; } /// - /// An array of child operations for this operation. + /// An array of child operations for this operation. Deprecated: please use . /// + [Obsolete($"This API has performance penalties, please use {nameof(ChildOperations)} instead.", error: false)] IEnumerable Children { get; } + /// + /// An enumerable of child operations for this operation. + /// + OperationList ChildOperations { get; } + /// /// The source language of the IOperation. Possible values are and . /// diff --git a/src/Compilers/Core/Portable/Operations/Operation.Enumerable.cs b/src/Compilers/Core/Portable/Operations/Operation.Enumerable.cs deleted file mode 100644 index a0e1ef8b253dd..0000000000000 --- a/src/Compilers/Core/Portable/Operations/Operation.Enumerable.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Collections; -using System; -using System.Diagnostics; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Operations; -using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis -{ - internal abstract partial class Operation : IOperation - { - /// - /// Implements a struct-based enumerable for nodes, using a slot-based system that tracks - /// the current slot, and the current index in the slot if the current slot is an immutable array. This type is not hardened - /// to default(Enumerable), and will null reference in these cases. - /// - [NonDefaultable] - internal readonly struct Enumerable : IEnumerable - { - private readonly Operation _operation; - - internal Enumerable(Operation operation) - { - _operation = operation; - } - - public Enumerator GetEnumerator() => new Enumerator(_operation); - - public ImmutableArray ToImmutableArray() - { - switch (_operation) - { - case NoneOperation { Children: var children }: - return children; - case InvalidOperation { Children: var children }: - return children; - case var _ when !GetEnumerator().MoveNext(): - return ImmutableArray.Empty; - default: - var builder = ArrayBuilder.GetInstance(); - foreach (var child in this) - { - builder.Add(child); - } - return builder.ToImmutableAndFree(); - } - } - - IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); - } - - /// - /// Implements a struct-based enumerator for nodes, using a slot-based system that tracks - /// the current slot, and the current index in the slot if the current slot is an immutable array. This type is not hardened - /// to default(Enumerator), and will null reference in these cases. Implementation of the - /// and members are delegated to the virtual and - /// methods, respectively. Calling after - /// has returned false will throw an . - /// - [NonDefaultable] - internal struct Enumerator : IEnumerator - { - private readonly Operation _operation; - private int _currentSlot; - private int _currentIndex; - - public Enumerator(Operation operation) - { - _operation = operation; - _currentSlot = -1; - _currentIndex = -1; - } - - public IOperation Current - { - get - { - Debug.Assert(_operation != null && _currentSlot >= 0 && _currentIndex >= 0); - return _operation.GetCurrent(_currentSlot, _currentIndex); - } - } - - public bool MoveNext() - { - bool result; - (result, _currentSlot, _currentIndex) = _operation.MoveNext(_currentSlot, _currentIndex); - return result; - } - - void IEnumerator.Reset() - { - _currentSlot = -1; - _currentIndex = -1; - } - - object? IEnumerator.Current => this.Current; - void IDisposable.Dispose() { } - } - } -} diff --git a/src/Compilers/Core/Portable/Operations/Operation.cs b/src/Compilers/Core/Portable/Operations/Operation.cs index 495b39d3e256c..0eac58b1f866a 100644 --- a/src/Compilers/Core/Portable/Operations/Operation.cs +++ b/src/Compilers/Core/Portable/Operations/Operation.cs @@ -2,13 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis { @@ -111,19 +112,21 @@ public Optional ConstantValue } } - /// - /// In the compiler layer, always prefer . - /// IEnumerable IOperation.Children => this.ChildOperations; - /// - /// Always prefer this over in the compiler layer, as this does not introduce allocations. - /// - // Making this public is tracked by https://github.com/dotnet/roslyn/issues/49475 - internal Operation.Enumerable ChildOperations => new Operation.Enumerable(this); + /// + public IOperation.OperationList ChildOperations => new IOperation.OperationList(this); - protected abstract IOperation GetCurrent(int slot, int index); - protected abstract (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex); + internal abstract int ChildOperationsCount { get; } + internal abstract IOperation GetCurrent(int slot, int index); + /// + /// A slot of -1 means start at the beginning. + /// + internal abstract (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex); + /// + /// A slot of int.MaxValue means start from the end. + /// + internal abstract (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex); SemanticModel? IOperation.SemanticModel => _owningSemanticModelOpt?.ContainingModelOrSelf; diff --git a/src/Compilers/Core/Portable/Operations/OperationExtensions.cs b/src/Compilers/Core/Portable/Operations/OperationExtensions.cs index 766431c4a3d17..dfba226daf6bb 100644 --- a/src/Compilers/Core/Portable/Operations/OperationExtensions.cs +++ b/src/Compilers/Core/Portable/Operations/OperationExtensions.cs @@ -93,7 +93,7 @@ private static IEnumerable Descendants(IOperation? operation, bool i yield return operation; } - var stack = ArrayBuilder.GetInstance(); + var stack = ArrayBuilder.GetInstance(); stack.Push(((Operation)operation).ChildOperations.GetEnumerator()); while (stack.Any()) diff --git a/src/Compilers/Core/Portable/Operations/OperationNodes.cs b/src/Compilers/Core/Portable/Operations/OperationNodes.cs index 0538014a37cb0..0b38583763bb1 100644 --- a/src/Compilers/Core/Portable/Operations/OperationNodes.cs +++ b/src/Compilers/Core/Portable/Operations/OperationNodes.cs @@ -25,7 +25,7 @@ public NoneOperation(ImmutableArray children, SemanticModel? semanti internal ImmutableArray Children { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Children.Length @@ -33,7 +33,9 @@ 0 when index < Children.Length _ => throw ExceptionUtilities.UnexpectedValue((slot, index)) }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override int ChildOperationsCount => Children.Length; + + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -50,6 +52,15 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + => previousSlot switch + { + int.MaxValue when !Children.IsEmpty => (true, 0, Children.Length - 1), + 0 when previousIndex > 0 => (true, 0, previousIndex - 1), + int.MaxValue or 0 or -1 => (false, -1, 0), + _ => throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)) + }; + public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.None; @@ -84,7 +95,7 @@ public InvalidOperation(ImmutableArray children, SemanticModel? sema internal ImmutableArray Children { get; } - protected override IOperation GetCurrent(int slot, int index) + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Children.Length @@ -92,7 +103,9 @@ 0 when index < Children.Length _ => throw ExceptionUtilities.UnexpectedValue((slot, index)) }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override int ChildOperationsCount => Children.Length; + + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -109,6 +122,15 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + => previousSlot switch + { + int.MaxValue when !Children.IsEmpty => (true, 0, Children.Length - 1), + 0 when previousIndex > 0 => (true, 0, previousIndex - 1), + int.MaxValue or 0 or -1 => (false, -1, 0), + _ => throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)) + }; + public override ITypeSymbol? Type { get; } internal override ConstantValue? OperationConstantValue { get; } public override OperationKind Kind => OperationKind.Invalid; @@ -137,13 +159,16 @@ public FlowAnonymousFunctionOperation(in ControlFlowGraphBuilder.Context context } public IMethodSymbol Symbol => Original.Symbol; - protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index)); + internal override int ChildOperationsCount => 0; + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue); public override OperationKind Kind => OperationKind.FlowAnonymousFunction; public override ITypeSymbol? Type => null; internal override ConstantValue? OperationConstantValue => null; + public override void Accept(OperationVisitor visitor) { visitor.VisitFlowAnonymousFunction(this); @@ -233,7 +258,9 @@ public DynamicObjectCreationOperation(IObjectOrCollectionInitializerOperation? i internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.DynamicObjectCreation; - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => (Initializer is null ? 0 : 1) + Arguments.Length; + + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when index < Arguments.Length @@ -243,7 +270,7 @@ 0 when index < Arguments.Length _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -267,6 +294,30 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (Initializer == null) goto case 1; + else return (true, 1, 0); + + case 1: + if (!Arguments.IsEmpty) return (true, 0, Arguments.Length - 1); + else goto case 0; + + case 0 when previousIndex > 0: + return (true, 0, previousIndex - 1); + + case 0: + case -1: + return (false, -1, 0); + + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } + public override void Accept(OperationVisitor visitor) { visitor.VisitDynamicObjectCreation(this); @@ -285,7 +336,9 @@ public DynamicInvocationOperation(IOperation operation, ImmutableArray (Operation is null ? 0 : 1) + Arguments.Length; + + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operation != null @@ -295,7 +348,8 @@ 1 when index < Arguments.Length _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -319,6 +373,30 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Arguments.IsEmpty) return (true, 1, Arguments.Length - 1); + else goto case 1; + + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + + case 1: + if (Operation != null) return (true, 0, 0); + else goto case 0; + + case 0: + case -1: + return (false, -1, 0); + + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } + public IOperation Operation { get; } internal override ConstantValue? OperationConstantValue => null; public override OperationKind Kind => OperationKind.DynamicInvocation; @@ -345,7 +423,9 @@ public DynamicIndexerAccessOperation(IOperation operation, ImmutableArray null; public override OperationKind Kind => OperationKind.DynamicIndexerAccess; - protected override IOperation GetCurrent(int slot, int index) + internal override int ChildOperationsCount => (Operation is null ? 0 : 1) + Arguments.Length; + + internal override IOperation GetCurrent(int slot, int index) => slot switch { 0 when Operation != null @@ -355,7 +435,7 @@ 1 when index < Arguments.Length _ => throw ExceptionUtilities.UnexpectedValue((slot, index)), }; - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { switch (previousSlot) { @@ -379,6 +459,30 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + switch (previousSlot) + { + case int.MaxValue: + if (!Arguments.IsEmpty) return (true, 1, Arguments.Length - 1); + else goto case 1; + + case 1 when previousIndex > 0: + return (true, 1, previousIndex - 1); + + case 1: + if (Operation != null) return (true, 0, 0); + else goto case 0; + + case 0: + case -1: + return (false, -1, 0); + + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } + public override void Accept(OperationVisitor visitor) { visitor.VisitDynamicIndexerAccess(this); @@ -406,7 +510,7 @@ internal sealed partial class ForToLoopOperation internal sealed partial class WhileLoopOperation { - protected override IOperation GetCurrent(int slot, int index) + internal override IOperation GetCurrent(int slot, int index) { return ConditionIsTop ? getCurrentSwitchTop() : getCurrentSwitchBottom(); @@ -435,7 +539,7 @@ IOperation getCurrentSwitchBottom() }; } - protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) { return ConditionIsTop ? moveNextConditionIsTop() : moveNextConditionIsBottom(); @@ -482,6 +586,53 @@ protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int prev } } + internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) + { + return ConditionIsTop ? moveNextConditionIsTop() : moveNextConditionIsBottom(); + + (bool hasNext, int nextSlot, int nextIndex) moveNextConditionIsTop() + { + switch (previousSlot) + { + case int.MaxValue: + if (IgnoredCondition != null) return (true, 2, 0); + else goto case 2; + case 2: + if (Body != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Condition != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } + + (bool hasNext, int nextSlot, int nextIndex) moveNextConditionIsBottom() + { + switch (previousSlot) + { + case int.MaxValue: + if (IgnoredCondition != null) return (true, 2, 0); + else goto case 2; + case 2: + if (Condition != null) return (true, 1, 0); + else goto case 1; + case 1: + if (Body != null) return (true, 0, 0); + else goto case 0; + case 0: + case -1: + return (false, -1, 0); + default: + throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex)); + } + } + } + public override LoopKind LoopKind => LoopKind.While; } diff --git a/src/Compilers/Core/Portable/PEWriter/InstructionOperandTypes.cs b/src/Compilers/Core/Portable/PEWriter/InstructionOperandTypes.cs index 4b34937925f21..dee800b95225f 100644 --- a/src/Compilers/Core/Portable/PEWriter/InstructionOperandTypes.cs +++ b/src/Compilers/Core/Portable/PEWriter/InstructionOperandTypes.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.Reflection.Emit; @@ -23,7 +24,7 @@ internal static OperandType ReadOperandType(ImmutableArray il, ref int pos } // internal for testing - internal static readonly byte[] OneByte = new byte[] + internal static ReadOnlySpan OneByte => new byte[] { (byte)OperandType.InlineNone, // nop (byte)OperandType.InlineNone, // break @@ -283,7 +284,7 @@ internal static OperandType ReadOperandType(ImmutableArray il, ref int pos }; // internal for testing - internal static readonly byte[] TwoByte = new byte[] + internal static ReadOnlySpan TwoByte => new byte[] { (byte)OperandType.InlineNone, // arglist (0xfe 0x00) (byte)OperandType.InlineNone, // ceq diff --git a/src/Compilers/Core/Portable/PublicAPI.Shipped.txt b/src/Compilers/Core/Portable/PublicAPI.Shipped.txt index 520dd569be017..863a907179f20 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Shipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Shipped.txt @@ -16,6 +16,7 @@ abstract Microsoft.CodeAnalysis.Compilation.GetMethodBodyDiagnostics(System.Thre abstract Microsoft.CodeAnalysis.Compilation.GetParseDiagnostics(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray abstract Microsoft.CodeAnalysis.Compilation.GetSymbolsWithName(string! name, Microsoft.CodeAnalysis.SymbolFilter filter = Microsoft.CodeAnalysis.SymbolFilter.TypeAndMember, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! abstract Microsoft.CodeAnalysis.Compilation.GetSymbolsWithName(System.Func! predicate, Microsoft.CodeAnalysis.SymbolFilter filter = Microsoft.CodeAnalysis.SymbolFilter.TypeAndMember, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! +abstract Microsoft.CodeAnalysis.Compilation.GetUsedAssemblyReferences(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray abstract Microsoft.CodeAnalysis.Compilation.IsCaseSensitive.get -> bool abstract Microsoft.CodeAnalysis.Compilation.Language.get -> string! abstract Microsoft.CodeAnalysis.Compilation.ReferencedAssemblyNames.get -> System.Collections.Generic.IEnumerable! @@ -160,6 +161,7 @@ abstract Microsoft.CodeAnalysis.SyntaxTree.GetDiagnostics(Microsoft.CodeAnalysis abstract Microsoft.CodeAnalysis.SyntaxTree.GetDiagnostics(Microsoft.CodeAnalysis.SyntaxToken token) -> System.Collections.Generic.IEnumerable! abstract Microsoft.CodeAnalysis.SyntaxTree.GetDiagnostics(Microsoft.CodeAnalysis.SyntaxTrivia trivia) -> System.Collections.Generic.IEnumerable! abstract Microsoft.CodeAnalysis.SyntaxTree.GetDiagnostics(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! +abstract Microsoft.CodeAnalysis.SyntaxTree.GetLineMappings(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! abstract Microsoft.CodeAnalysis.SyntaxTree.GetLineSpan(Microsoft.CodeAnalysis.Text.TextSpan span, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FileLinePositionSpan abstract Microsoft.CodeAnalysis.SyntaxTree.GetLocation(Microsoft.CodeAnalysis.Text.TextSpan span) -> Microsoft.CodeAnalysis.Location! abstract Microsoft.CodeAnalysis.SyntaxTree.GetMappedLineSpan(Microsoft.CodeAnalysis.Text.TextSpan span, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FileLinePositionSpan @@ -196,12 +198,20 @@ const Microsoft.CodeAnalysis.LanguageNames.FSharp = "F#" -> string! const Microsoft.CodeAnalysis.LanguageNames.VisualBasic = "Visual Basic" -> string! const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.AnalyzerException = "AnalyzerException" -> string! const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.Build = "Build" -> string! +const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.CompilationEnd = "CompilationEnd" -> string! const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.Compiler = "Compiler" -> string! const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.CustomObsolete = "CustomObsolete" -> string! const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.EditAndContinue = "EditAndContinue" -> string! const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.NotConfigurable = "NotConfigurable" -> string! const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.Telemetry = "Telemetry" -> string! const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.Unnecessary = "Unnecessary" -> string! +const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.AdditionalTexts = "AdditionalTexts" -> string! +const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.AnalyzerConfigOptions = "AnalyzerConfigOptions" -> string! +const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.Compilation = "Compilation" -> string! +const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.MetadataReferences = "MetadataReferences" -> string! +const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.ParseOptions = "ParseOptions" -> string! +const Microsoft.CodeAnalysis.WellKnownGeneratorOutputs.ImplementationSourceOutput = "ImplementationSourceOutput" -> string! +const Microsoft.CodeAnalysis.WellKnownGeneratorOutputs.SourceOutput = "SourceOutput" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.AdditionOperatorName = "op_Addition" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.BitwiseAndOperatorName = "op_BitwiseAnd" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.BitwiseOrOperatorName = "op_BitwiseOr" -> string! @@ -256,6 +266,7 @@ const Microsoft.CodeAnalysis.WellKnownMemberNames.ObjectGetHashCode = "GetHashCo const Microsoft.CodeAnalysis.WellKnownMemberNames.ObjectToString = "ToString" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.OnCompleted = "OnCompleted" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.OnesComplementOperatorName = "op_OnesComplement" -> string! +const Microsoft.CodeAnalysis.WellKnownMemberNames.PrintMembersMethodName = "PrintMembers" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.RightShiftOperatorName = "op_RightShift" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.SliceMethodName = "Slice" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.StaticConstructorName = ".cctor" -> string! @@ -482,6 +493,7 @@ Microsoft.CodeAnalysis.Compilation.Emit(System.IO.Stream! peStream, System.IO.St Microsoft.CodeAnalysis.Compilation.Emit(System.IO.Stream! peStream, System.IO.Stream! pdbStream, System.IO.Stream! xmlDocumentationStream, System.IO.Stream! win32Resources, System.Collections.Generic.IEnumerable! manifestResources, Microsoft.CodeAnalysis.Emit.EmitOptions! options, Microsoft.CodeAnalysis.IMethodSymbol! debugEntryPoint, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.Emit.EmitResult! Microsoft.CodeAnalysis.Compilation.Emit(System.IO.Stream! peStream, System.IO.Stream? pdbStream, System.IO.Stream? xmlDocumentationStream, System.IO.Stream? win32Resources, System.Collections.Generic.IEnumerable? manifestResources, Microsoft.CodeAnalysis.Emit.EmitOptions! options, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.Emit.EmitResult! Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, System.Collections.Generic.ICollection! updatedMethods, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! +Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, System.Collections.Generic.ICollection! updatedMethods, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! Microsoft.CodeAnalysis.Compilation.ExternalReferences.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.Compilation.GetAssemblyOrModuleSymbol(Microsoft.CodeAnalysis.MetadataReference! reference) -> Microsoft.CodeAnalysis.ISymbol? @@ -913,6 +925,8 @@ Microsoft.CodeAnalysis.Emit.EmitBaseline Microsoft.CodeAnalysis.Emit.EmitBaseline.OriginalMetadata.get -> Microsoft.CodeAnalysis.ModuleMetadata! Microsoft.CodeAnalysis.Emit.EmitDifferenceResult Microsoft.CodeAnalysis.Emit.EmitDifferenceResult.Baseline.get -> Microsoft.CodeAnalysis.Emit.EmitBaseline? +Microsoft.CodeAnalysis.Emit.EmitDifferenceResult.ChangedTypes.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.Emit.EmitDifferenceResult.UpdatedMethods.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.Emit.EmitOptions Microsoft.CodeAnalysis.Emit.EmitOptions.BaseAddress.get -> ulong Microsoft.CodeAnalysis.Emit.EmitOptions.DebugInformationFormat.get -> Microsoft.CodeAnalysis.Emit.DebugInformationFormat @@ -968,6 +982,7 @@ Microsoft.CodeAnalysis.Emit.SemanticEditKind Microsoft.CodeAnalysis.Emit.SemanticEditKind.Delete = 3 -> Microsoft.CodeAnalysis.Emit.SemanticEditKind Microsoft.CodeAnalysis.Emit.SemanticEditKind.Insert = 2 -> Microsoft.CodeAnalysis.Emit.SemanticEditKind Microsoft.CodeAnalysis.Emit.SemanticEditKind.None = 0 -> Microsoft.CodeAnalysis.Emit.SemanticEditKind +Microsoft.CodeAnalysis.Emit.SemanticEditKind.Replace = 4 -> Microsoft.CodeAnalysis.Emit.SemanticEditKind Microsoft.CodeAnalysis.Emit.SemanticEditKind.Update = 1 -> Microsoft.CodeAnalysis.Emit.SemanticEditKind Microsoft.CodeAnalysis.ErrorLogOptions Microsoft.CodeAnalysis.ErrorLogOptions.ErrorLogOptions(string! path, Microsoft.CodeAnalysis.SarifVersion sarifVersion) -> void @@ -1063,6 +1078,7 @@ Microsoft.CodeAnalysis.FlowAnalysis.IFlowCaptureOperation.Id.get -> Microsoft.Co Microsoft.CodeAnalysis.FlowAnalysis.IFlowCaptureOperation.Value.get -> Microsoft.CodeAnalysis.IOperation! Microsoft.CodeAnalysis.FlowAnalysis.IFlowCaptureReferenceOperation Microsoft.CodeAnalysis.FlowAnalysis.IFlowCaptureReferenceOperation.Id.get -> Microsoft.CodeAnalysis.FlowAnalysis.CaptureId +Microsoft.CodeAnalysis.FlowAnalysis.IFlowCaptureReferenceOperation.IsInitialization.get -> bool Microsoft.CodeAnalysis.FlowAnalysis.IIsNullOperation Microsoft.CodeAnalysis.FlowAnalysis.IIsNullOperation.Operand.get -> Microsoft.CodeAnalysis.IOperation! Microsoft.CodeAnalysis.FlowAnalysis.IStaticLocalInitializationSemaphoreOperation @@ -1078,14 +1094,24 @@ Microsoft.CodeAnalysis.GeneratedSourceResult.SourceText.get -> Microsoft.CodeAna Microsoft.CodeAnalysis.GeneratedSourceResult.SyntaxTree.get -> Microsoft.CodeAnalysis.SyntaxTree! Microsoft.CodeAnalysis.GeneratorAttribute Microsoft.CodeAnalysis.GeneratorAttribute.GeneratorAttribute() -> void +Microsoft.CodeAnalysis.GeneratorAttribute.GeneratorAttribute(string! firstLanguage, params string![]! additionalLanguages) -> void +Microsoft.CodeAnalysis.GeneratorAttribute.Languages.get -> string![]! Microsoft.CodeAnalysis.GeneratorDriver Microsoft.CodeAnalysis.GeneratorDriver.AddAdditionalTexts(System.Collections.Immutable.ImmutableArray additionalTexts) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.AddGenerators(System.Collections.Immutable.ImmutableArray generators) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.GetRunResult() -> Microsoft.CodeAnalysis.GeneratorDriverRunResult! Microsoft.CodeAnalysis.GeneratorDriver.RemoveAdditionalTexts(System.Collections.Immutable.ImmutableArray additionalTexts) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.RemoveGenerators(System.Collections.Immutable.ImmutableArray generators) -> Microsoft.CodeAnalysis.GeneratorDriver! +Microsoft.CodeAnalysis.GeneratorDriver.ReplaceAdditionalText(Microsoft.CodeAnalysis.AdditionalText! oldText, Microsoft.CodeAnalysis.AdditionalText! newText) -> Microsoft.CodeAnalysis.GeneratorDriver! +Microsoft.CodeAnalysis.GeneratorDriver.ReplaceAdditionalTexts(System.Collections.Immutable.ImmutableArray newTexts) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.RunGeneratorsAndUpdateCompilation(Microsoft.CodeAnalysis.Compilation! compilation, out Microsoft.CodeAnalysis.Compilation! outputCompilation, out System.Collections.Immutable.ImmutableArray diagnostics, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver! +Microsoft.CodeAnalysis.GeneratorDriver.WithUpdatedAnalyzerConfigOptions(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider! newOptions) -> Microsoft.CodeAnalysis.GeneratorDriver! +Microsoft.CodeAnalysis.GeneratorDriver.WithUpdatedParseOptions(Microsoft.CodeAnalysis.ParseOptions! newOptions) -> Microsoft.CodeAnalysis.GeneratorDriver! +Microsoft.CodeAnalysis.GeneratorDriverOptions +Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions() -> void +Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions(Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind disabledOutputs, bool trackIncrementalGeneratorSteps) -> void +Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions(Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind disabledOutputs) -> void Microsoft.CodeAnalysis.GeneratorDriverRunResult Microsoft.CodeAnalysis.GeneratorDriverRunResult.Diagnostics.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.GeneratorDriverRunResult.GeneratedTrees.get -> System.Collections.Immutable.ImmutableArray @@ -1100,17 +1126,32 @@ Microsoft.CodeAnalysis.GeneratorExecutionContext.Compilation.get -> Microsoft.Co Microsoft.CodeAnalysis.GeneratorExecutionContext.GeneratorExecutionContext() -> void Microsoft.CodeAnalysis.GeneratorExecutionContext.ParseOptions.get -> Microsoft.CodeAnalysis.ParseOptions! Microsoft.CodeAnalysis.GeneratorExecutionContext.ReportDiagnostic(Microsoft.CodeAnalysis.Diagnostic! diagnostic) -> void +Microsoft.CodeAnalysis.GeneratorExecutionContext.SyntaxContextReceiver.get -> Microsoft.CodeAnalysis.ISyntaxContextReceiver? Microsoft.CodeAnalysis.GeneratorExecutionContext.SyntaxReceiver.get -> Microsoft.CodeAnalysis.ISyntaxReceiver? +Microsoft.CodeAnalysis.GeneratorExtensions Microsoft.CodeAnalysis.GeneratorInitializationContext Microsoft.CodeAnalysis.GeneratorInitializationContext.CancellationToken.get -> System.Threading.CancellationToken Microsoft.CodeAnalysis.GeneratorInitializationContext.GeneratorInitializationContext() -> void +Microsoft.CodeAnalysis.GeneratorInitializationContext.RegisterForPostInitialization(System.Action! callback) -> void +Microsoft.CodeAnalysis.GeneratorInitializationContext.RegisterForSyntaxNotifications(Microsoft.CodeAnalysis.SyntaxContextReceiverCreator! receiverCreator) -> void Microsoft.CodeAnalysis.GeneratorInitializationContext.RegisterForSyntaxNotifications(Microsoft.CodeAnalysis.SyntaxReceiverCreator! receiverCreator) -> void +Microsoft.CodeAnalysis.GeneratorPostInitializationContext +Microsoft.CodeAnalysis.GeneratorPostInitializationContext.AddSource(string! hintName, Microsoft.CodeAnalysis.Text.SourceText! sourceText) -> void +Microsoft.CodeAnalysis.GeneratorPostInitializationContext.AddSource(string! hintName, string! source) -> void +Microsoft.CodeAnalysis.GeneratorPostInitializationContext.CancellationToken.get -> System.Threading.CancellationToken +Microsoft.CodeAnalysis.GeneratorPostInitializationContext.GeneratorPostInitializationContext() -> void Microsoft.CodeAnalysis.GeneratorRunResult Microsoft.CodeAnalysis.GeneratorRunResult.Diagnostics.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.GeneratorRunResult.Exception.get -> System.Exception? Microsoft.CodeAnalysis.GeneratorRunResult.GeneratedSources.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.GeneratorRunResult.Generator.get -> Microsoft.CodeAnalysis.ISourceGenerator! Microsoft.CodeAnalysis.GeneratorRunResult.GeneratorRunResult() -> void +Microsoft.CodeAnalysis.GeneratorRunResult.TrackedOutputSteps.get -> System.Collections.Immutable.ImmutableDictionary>! +Microsoft.CodeAnalysis.GeneratorRunResult.TrackedSteps.get -> System.Collections.Immutable.ImmutableDictionary>! +Microsoft.CodeAnalysis.GeneratorSyntaxContext +Microsoft.CodeAnalysis.GeneratorSyntaxContext.GeneratorSyntaxContext() -> void +Microsoft.CodeAnalysis.GeneratorSyntaxContext.Node.get -> Microsoft.CodeAnalysis.SyntaxNode! +Microsoft.CodeAnalysis.GeneratorSyntaxContext.SemanticModel.get -> Microsoft.CodeAnalysis.SemanticModel! Microsoft.CodeAnalysis.IAliasSymbol Microsoft.CodeAnalysis.IAliasSymbol.Target.get -> Microsoft.CodeAnalysis.INamespaceOrTypeSymbol! Microsoft.CodeAnalysis.IAnalyzerAssemblyLoader @@ -1162,8 +1203,10 @@ Microsoft.CodeAnalysis.IFieldSymbol.AssociatedSymbol.get -> Microsoft.CodeAnalys Microsoft.CodeAnalysis.IFieldSymbol.ConstantValue.get -> object? Microsoft.CodeAnalysis.IFieldSymbol.CorrespondingTupleField.get -> Microsoft.CodeAnalysis.IFieldSymbol? Microsoft.CodeAnalysis.IFieldSymbol.CustomModifiers.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.IFieldSymbol.FixedSize.get -> int Microsoft.CodeAnalysis.IFieldSymbol.HasConstantValue.get -> bool Microsoft.CodeAnalysis.IFieldSymbol.IsConst.get -> bool +Microsoft.CodeAnalysis.IFieldSymbol.IsExplicitlyNamedTupleElement.get -> bool Microsoft.CodeAnalysis.IFieldSymbol.IsFixedSizeBuffer.get -> bool Microsoft.CodeAnalysis.IFieldSymbol.IsReadOnly.get -> bool Microsoft.CodeAnalysis.IFieldSymbol.IsVolatile.get -> bool @@ -1172,6 +1215,8 @@ Microsoft.CodeAnalysis.IFieldSymbol.OriginalDefinition.get -> Microsoft.CodeAnal Microsoft.CodeAnalysis.IFieldSymbol.Type.get -> Microsoft.CodeAnalysis.ITypeSymbol! Microsoft.CodeAnalysis.IFunctionPointerTypeSymbol Microsoft.CodeAnalysis.IFunctionPointerTypeSymbol.Signature.get -> Microsoft.CodeAnalysis.IMethodSymbol! +Microsoft.CodeAnalysis.IIncrementalGenerator +Microsoft.CodeAnalysis.IIncrementalGenerator.Initialize(Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext context) -> void Microsoft.CodeAnalysis.ILabelSymbol Microsoft.CodeAnalysis.ILabelSymbol.ContainingMethod.get -> Microsoft.CodeAnalysis.IMethodSymbol! Microsoft.CodeAnalysis.ILocalSymbol @@ -1203,8 +1248,10 @@ Microsoft.CodeAnalysis.IMethodSymbol.IsConditional.get -> bool Microsoft.CodeAnalysis.IMethodSymbol.IsExtensionMethod.get -> bool Microsoft.CodeAnalysis.IMethodSymbol.IsGenericMethod.get -> bool Microsoft.CodeAnalysis.IMethodSymbol.IsInitOnly.get -> bool +Microsoft.CodeAnalysis.IMethodSymbol.IsPartialDefinition.get -> bool Microsoft.CodeAnalysis.IMethodSymbol.IsReadOnly.get -> bool Microsoft.CodeAnalysis.IMethodSymbol.IsVararg.get -> bool +Microsoft.CodeAnalysis.IMethodSymbol.MethodImplementationFlags.get -> System.Reflection.MethodImplAttributes Microsoft.CodeAnalysis.IMethodSymbol.MethodKind.get -> Microsoft.CodeAnalysis.MethodKind Microsoft.CodeAnalysis.IMethodSymbol.OriginalDefinition.get -> Microsoft.CodeAnalysis.IMethodSymbol! Microsoft.CodeAnalysis.IMethodSymbol.OverriddenMethod.get -> Microsoft.CodeAnalysis.IMethodSymbol? @@ -1277,6 +1324,45 @@ Microsoft.CodeAnalysis.INamespaceSymbol.GetMembers(string! name) -> System.Colle Microsoft.CodeAnalysis.INamespaceSymbol.GetNamespaceMembers() -> System.Collections.Generic.IEnumerable! Microsoft.CodeAnalysis.INamespaceSymbol.IsGlobalNamespace.get -> bool Microsoft.CodeAnalysis.INamespaceSymbol.NamespaceKind.get -> Microsoft.CodeAnalysis.NamespaceKind +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.AdditionalTextsProvider.get -> Microsoft.CodeAnalysis.IncrementalValuesProvider +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.AnalyzerConfigOptionsProvider.get -> Microsoft.CodeAnalysis.IncrementalValueProvider +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.CompilationProvider.get -> Microsoft.CodeAnalysis.IncrementalValueProvider +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.IncrementalGeneratorInitializationContext() -> void +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.MetadataReferencesProvider.get -> Microsoft.CodeAnalysis.IncrementalValuesProvider +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.ParseOptionsProvider.get -> Microsoft.CodeAnalysis.IncrementalValueProvider +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterImplementationSourceOutput(Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Action! action) -> void +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterImplementationSourceOutput(Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Action! action) -> void +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterPostInitializationOutput(System.Action! callback) -> void +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterSourceOutput(Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Action! action) -> void +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterSourceOutput(Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Action! action) -> void +Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.SyntaxProvider.get -> Microsoft.CodeAnalysis.SyntaxValueProvider +Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind +Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.Implementation = 4 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind +Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.None = 0 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind +Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.PostInit = 2 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind +Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.Source = 1 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind +Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext +Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.AddSource(string! hintName, Microsoft.CodeAnalysis.Text.SourceText! sourceText) -> void +Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.AddSource(string! hintName, string! source) -> void +Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.CancellationToken.get -> System.Threading.CancellationToken +Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.IncrementalGeneratorPostInitializationContext() -> void +Microsoft.CodeAnalysis.IncrementalGeneratorRunStep +Microsoft.CodeAnalysis.IncrementalGeneratorRunStep.ElapsedTime.get -> System.TimeSpan +Microsoft.CodeAnalysis.IncrementalGeneratorRunStep.Inputs.get -> System.Collections.Immutable.ImmutableArray<(Microsoft.CodeAnalysis.IncrementalGeneratorRunStep! Source, int OutputIndex)> +Microsoft.CodeAnalysis.IncrementalGeneratorRunStep.Name.get -> string? +Microsoft.CodeAnalysis.IncrementalGeneratorRunStep.Outputs.get -> System.Collections.Immutable.ImmutableArray<(object! Value, Microsoft.CodeAnalysis.IncrementalStepRunReason Reason)> +Microsoft.CodeAnalysis.IncrementalStepRunReason +Microsoft.CodeAnalysis.IncrementalStepRunReason.Cached = 3 -> Microsoft.CodeAnalysis.IncrementalStepRunReason +Microsoft.CodeAnalysis.IncrementalStepRunReason.Modified = 1 -> Microsoft.CodeAnalysis.IncrementalStepRunReason +Microsoft.CodeAnalysis.IncrementalStepRunReason.New = 0 -> Microsoft.CodeAnalysis.IncrementalStepRunReason +Microsoft.CodeAnalysis.IncrementalStepRunReason.Removed = 4 -> Microsoft.CodeAnalysis.IncrementalStepRunReason +Microsoft.CodeAnalysis.IncrementalStepRunReason.Unchanged = 2 -> Microsoft.CodeAnalysis.IncrementalStepRunReason +Microsoft.CodeAnalysis.IncrementalValueProvider +Microsoft.CodeAnalysis.IncrementalValueProvider.IncrementalValueProvider() -> void +Microsoft.CodeAnalysis.IncrementalValueProviderExtensions +Microsoft.CodeAnalysis.IncrementalValuesProvider +Microsoft.CodeAnalysis.IncrementalValuesProvider.IncrementalValuesProvider() -> void Microsoft.CodeAnalysis.IOperation Microsoft.CodeAnalysis.IOperation.Accept(Microsoft.CodeAnalysis.Operations.OperationVisitor! visitor) -> void Microsoft.CodeAnalysis.IOperation.Accept(Microsoft.CodeAnalysis.Operations.OperationVisitor! visitor, TArgument argument) -> TResult? @@ -1363,6 +1449,7 @@ Microsoft.CodeAnalysis.ISymbol.Kind.get -> Microsoft.CodeAnalysis.SymbolKind Microsoft.CodeAnalysis.ISymbol.Language.get -> string! Microsoft.CodeAnalysis.ISymbol.Locations.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.ISymbol.MetadataName.get -> string! +Microsoft.CodeAnalysis.ISymbol.MetadataToken.get -> int Microsoft.CodeAnalysis.ISymbol.Name.get -> string! Microsoft.CodeAnalysis.ISymbol.OriginalDefinition.get -> Microsoft.CodeAnalysis.ISymbol! Microsoft.CodeAnalysis.ISymbol.ToDisplayParts(Microsoft.CodeAnalysis.SymbolDisplayFormat? format = null) -> System.Collections.Immutable.ImmutableArray @@ -1370,6 +1457,8 @@ Microsoft.CodeAnalysis.ISymbol.ToDisplayString(Microsoft.CodeAnalysis.SymbolDisp Microsoft.CodeAnalysis.ISymbol.ToMinimalDisplayParts(Microsoft.CodeAnalysis.SemanticModel! semanticModel, int position, Microsoft.CodeAnalysis.SymbolDisplayFormat? format = null) -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.ISymbol.ToMinimalDisplayString(Microsoft.CodeAnalysis.SemanticModel! semanticModel, int position, Microsoft.CodeAnalysis.SymbolDisplayFormat? format = null) -> string! Microsoft.CodeAnalysis.ISymbolExtensions +Microsoft.CodeAnalysis.ISyntaxContextReceiver +Microsoft.CodeAnalysis.ISyntaxContextReceiver.OnVisitSyntaxNode(Microsoft.CodeAnalysis.GeneratorSyntaxContext context) -> void Microsoft.CodeAnalysis.ISyntaxReceiver Microsoft.CodeAnalysis.ISyntaxReceiver.OnVisitSyntaxNode(Microsoft.CodeAnalysis.SyntaxNode! syntaxNode) -> void Microsoft.CodeAnalysis.ITypeParameterSymbol @@ -1396,6 +1485,7 @@ Microsoft.CodeAnalysis.ITypeSymbol.Interfaces.get -> System.Collections.Immutabl Microsoft.CodeAnalysis.ITypeSymbol.IsAnonymousType.get -> bool Microsoft.CodeAnalysis.ITypeSymbol.IsNativeIntegerType.get -> bool Microsoft.CodeAnalysis.ITypeSymbol.IsReadOnly.get -> bool +Microsoft.CodeAnalysis.ITypeSymbol.IsRecord.get -> bool Microsoft.CodeAnalysis.ITypeSymbol.IsReferenceType.get -> bool Microsoft.CodeAnalysis.ITypeSymbol.IsRefLikeType.get -> bool Microsoft.CodeAnalysis.ITypeSymbol.IsTupleType.get -> bool @@ -1411,6 +1501,14 @@ Microsoft.CodeAnalysis.ITypeSymbol.ToMinimalDisplayString(Microsoft.CodeAnalysis Microsoft.CodeAnalysis.ITypeSymbol.TypeKind.get -> Microsoft.CodeAnalysis.TypeKind Microsoft.CodeAnalysis.ITypeSymbol.WithNullableAnnotation(Microsoft.CodeAnalysis.NullableAnnotation nullableAnnotation) -> Microsoft.CodeAnalysis.ITypeSymbol! Microsoft.CodeAnalysis.LanguageNames +Microsoft.CodeAnalysis.LineMapping +Microsoft.CodeAnalysis.LineMapping.CharacterOffset.get -> int? +Microsoft.CodeAnalysis.LineMapping.Equals(Microsoft.CodeAnalysis.LineMapping other) -> bool +Microsoft.CodeAnalysis.LineMapping.IsHidden.get -> bool +Microsoft.CodeAnalysis.LineMapping.LineMapping() -> void +Microsoft.CodeAnalysis.LineMapping.LineMapping(Microsoft.CodeAnalysis.Text.LinePositionSpan span, int? characterOffset, Microsoft.CodeAnalysis.FileLinePositionSpan mappedSpan) -> void +Microsoft.CodeAnalysis.LineMapping.MappedSpan.get -> Microsoft.CodeAnalysis.FileLinePositionSpan +Microsoft.CodeAnalysis.LineMapping.Span.get -> Microsoft.CodeAnalysis.Text.LinePositionSpan Microsoft.CodeAnalysis.LineVisibility Microsoft.CodeAnalysis.LineVisibility.BeforeFirstLineDirective = 0 -> Microsoft.CodeAnalysis.LineVisibility Microsoft.CodeAnalysis.LineVisibility.Hidden = 1 -> Microsoft.CodeAnalysis.LineVisibility @@ -1575,9 +1673,17 @@ Microsoft.CodeAnalysis.OperationKind.FieldReference = 26 -> Microsoft.CodeAnalys Microsoft.CodeAnalysis.OperationKind.FlowAnonymousFunction = 96 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.FlowCapture = 91 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.FlowCaptureReference = 92 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.FunctionPointerInvocation = 120 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.ImplicitIndexerReference = 123 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.Increment = 66 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.InstanceReference = 39 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.InterpolatedString = 48 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.InterpolatedStringAddition = 115 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.InterpolatedStringAppendFormatted = 117 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.InterpolatedStringAppendInvalid = 118 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.InterpolatedStringAppendLiteral = 116 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.InterpolatedStringHandlerArgumentPlaceholder = 119 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.InterpolatedStringHandlerCreation = 114 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.InterpolatedStringText = 83 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.Interpolation = 84 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.Invalid = 1 -> Microsoft.CodeAnalysis.OperationKind @@ -1586,6 +1692,7 @@ Microsoft.CodeAnalysis.OperationKind.IsNull = 93 -> Microsoft.CodeAnalysis.Opera Microsoft.CodeAnalysis.OperationKind.IsPattern = 65 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.IsType = 40 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.Labeled = 6 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.ListPattern = 121 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.Literal = 20 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.LocalFunction = 16 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.LocalReference = 24 -> Microsoft.CodeAnalysis.OperationKind @@ -1616,6 +1723,7 @@ Microsoft.CodeAnalysis.OperationKind.RelationalPattern = 112 -> Microsoft.CodeAn Microsoft.CodeAnalysis.OperationKind.Return = 9 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.SimpleAssignment = 42 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.SizeOf = 63 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.OperationKind.SlicePattern = 122 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.StaticLocalInitializationSemaphore = 95 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.Stop = 17 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.Switch = 4 -> Microsoft.CodeAnalysis.OperationKind @@ -1844,6 +1952,14 @@ Microsoft.CodeAnalysis.Operations.IForToLoopOperation.LimitValue.get -> Microsof Microsoft.CodeAnalysis.Operations.IForToLoopOperation.LoopControlVariable.get -> Microsoft.CodeAnalysis.IOperation! Microsoft.CodeAnalysis.Operations.IForToLoopOperation.NextVariables.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.Operations.IForToLoopOperation.StepValue.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation +Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation.Arguments.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation.Target.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation +Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation.Argument.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation.IndexerSymbol.get -> Microsoft.CodeAnalysis.ISymbol! +Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation.Instance.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation.LengthSymbol.get -> Microsoft.CodeAnalysis.ISymbol! Microsoft.CodeAnalysis.Operations.IIncrementOrDecrementOperation Microsoft.CodeAnalysis.Operations.IIncrementOrDecrementOperation.IsChecked.get -> bool Microsoft.CodeAnalysis.Operations.IIncrementOrDecrementOperation.IsLifted.get -> bool @@ -1852,7 +1968,20 @@ Microsoft.CodeAnalysis.Operations.IIncrementOrDecrementOperation.OperatorMethod. Microsoft.CodeAnalysis.Operations.IIncrementOrDecrementOperation.Target.get -> Microsoft.CodeAnalysis.IOperation! Microsoft.CodeAnalysis.Operations.IInstanceReferenceOperation Microsoft.CodeAnalysis.Operations.IInstanceReferenceOperation.ReferenceKind.get -> Microsoft.CodeAnalysis.Operations.InstanceReferenceKind +Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation +Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation.Left.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation.Right.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.Operations.IInterpolatedStringAppendOperation +Microsoft.CodeAnalysis.Operations.IInterpolatedStringAppendOperation.AppendCall.get -> Microsoft.CodeAnalysis.IOperation! Microsoft.CodeAnalysis.Operations.IInterpolatedStringContentOperation +Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation +Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation.ArgumentIndex.get -> int +Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation.PlaceholderKind.get -> Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind +Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation +Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation.Content.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation.HandlerAppendCallsReturnBool.get -> bool +Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation.HandlerCreation.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation.HandlerCreationHasSuccessParameter.get -> bool Microsoft.CodeAnalysis.Operations.IInterpolatedStringOperation Microsoft.CodeAnalysis.Operations.IInterpolatedStringOperation.Parts.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.Operations.IInterpolatedStringTextOperation @@ -1877,6 +2006,11 @@ Microsoft.CodeAnalysis.Operations.IIsTypeOperation.ValueOperand.get -> Microsoft Microsoft.CodeAnalysis.Operations.ILabeledOperation Microsoft.CodeAnalysis.Operations.ILabeledOperation.Label.get -> Microsoft.CodeAnalysis.ILabelSymbol! Microsoft.CodeAnalysis.Operations.ILabeledOperation.Operation.get -> Microsoft.CodeAnalysis.IOperation? +Microsoft.CodeAnalysis.Operations.IListPatternOperation +Microsoft.CodeAnalysis.Operations.IListPatternOperation.DeclaredSymbol.get -> Microsoft.CodeAnalysis.ISymbol? +Microsoft.CodeAnalysis.Operations.IListPatternOperation.IndexerSymbol.get -> Microsoft.CodeAnalysis.ISymbol? +Microsoft.CodeAnalysis.Operations.IListPatternOperation.LengthSymbol.get -> Microsoft.CodeAnalysis.ISymbol? +Microsoft.CodeAnalysis.Operations.IListPatternOperation.Patterns.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.Operations.ILiteralOperation Microsoft.CodeAnalysis.Operations.ILocalFunctionOperation Microsoft.CodeAnalysis.Operations.ILocalFunctionOperation.Body.get -> Microsoft.CodeAnalysis.Operations.IBlockOperation? @@ -1914,7 +2048,12 @@ Microsoft.CodeAnalysis.Operations.INegatedPatternOperation.Pattern.get -> Micros Microsoft.CodeAnalysis.Operations.InstanceReferenceKind Microsoft.CodeAnalysis.Operations.InstanceReferenceKind.ContainingTypeInstance = 0 -> Microsoft.CodeAnalysis.Operations.InstanceReferenceKind Microsoft.CodeAnalysis.Operations.InstanceReferenceKind.ImplicitReceiver = 1 -> Microsoft.CodeAnalysis.Operations.InstanceReferenceKind +Microsoft.CodeAnalysis.Operations.InstanceReferenceKind.InterpolatedStringHandler = 3 -> Microsoft.CodeAnalysis.Operations.InstanceReferenceKind Microsoft.CodeAnalysis.Operations.InstanceReferenceKind.PatternInput = 2 -> Microsoft.CodeAnalysis.Operations.InstanceReferenceKind +Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind +Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind.CallsiteArgument = 0 -> Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind +Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind.CallsiteReceiver = 1 -> Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind +Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument = 2 -> Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind Microsoft.CodeAnalysis.Operations.IObjectCreationOperation Microsoft.CodeAnalysis.Operations.IObjectCreationOperation.Arguments.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.Operations.IObjectCreationOperation.Constructor.get -> Microsoft.CodeAnalysis.IMethodSymbol? @@ -1980,6 +2119,9 @@ Microsoft.CodeAnalysis.Operations.ISingleValueCaseClauseOperation Microsoft.CodeAnalysis.Operations.ISingleValueCaseClauseOperation.Value.get -> Microsoft.CodeAnalysis.IOperation! Microsoft.CodeAnalysis.Operations.ISizeOfOperation Microsoft.CodeAnalysis.Operations.ISizeOfOperation.TypeOperand.get -> Microsoft.CodeAnalysis.ITypeSymbol! +Microsoft.CodeAnalysis.Operations.ISlicePatternOperation +Microsoft.CodeAnalysis.Operations.ISlicePatternOperation.Pattern.get -> Microsoft.CodeAnalysis.Operations.IPatternOperation? +Microsoft.CodeAnalysis.Operations.ISlicePatternOperation.SliceSymbol.get -> Microsoft.CodeAnalysis.ISymbol? Microsoft.CodeAnalysis.Operations.IStopOperation Microsoft.CodeAnalysis.Operations.ISwitchCaseOperation Microsoft.CodeAnalysis.Operations.ISwitchCaseOperation.Body.get -> System.Collections.Immutable.ImmutableArray @@ -1992,6 +2134,7 @@ Microsoft.CodeAnalysis.Operations.ISwitchExpressionArmOperation.Pattern.get -> M Microsoft.CodeAnalysis.Operations.ISwitchExpressionArmOperation.Value.get -> Microsoft.CodeAnalysis.IOperation! Microsoft.CodeAnalysis.Operations.ISwitchExpressionOperation Microsoft.CodeAnalysis.Operations.ISwitchExpressionOperation.Arms.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.Operations.ISwitchExpressionOperation.IsExhaustive.get -> bool Microsoft.CodeAnalysis.Operations.ISwitchExpressionOperation.Value.get -> Microsoft.CodeAnalysis.IOperation! Microsoft.CodeAnalysis.Operations.ISwitchOperation Microsoft.CodeAnalysis.Operations.ISwitchOperation.Cases.get -> System.Collections.Immutable.ImmutableArray @@ -2070,6 +2213,8 @@ Microsoft.CodeAnalysis.Operations.OperationVisitor Microsoft.CodeAnalysis.Operations.OperationVisitor.OperationVisitor() -> void Microsoft.CodeAnalysis.Operations.OperationWalker Microsoft.CodeAnalysis.Operations.OperationWalker.OperationWalker() -> void +Microsoft.CodeAnalysis.Operations.OperationWalker +Microsoft.CodeAnalysis.Operations.OperationWalker.OperationWalker() -> void Microsoft.CodeAnalysis.Operations.UnaryOperatorKind Microsoft.CodeAnalysis.Operations.UnaryOperatorKind.BitwiseNegation = 1 -> Microsoft.CodeAnalysis.Operations.UnaryOperatorKind Microsoft.CodeAnalysis.Operations.UnaryOperatorKind.False = 6 -> Microsoft.CodeAnalysis.Operations.UnaryOperatorKind @@ -2228,6 +2373,12 @@ Microsoft.CodeAnalysis.SourceFileResolver.SearchPaths.get -> System.Collections. Microsoft.CodeAnalysis.SourceFileResolver.SourceFileResolver(System.Collections.Generic.IEnumerable! searchPaths, string? baseDirectory) -> void Microsoft.CodeAnalysis.SourceFileResolver.SourceFileResolver(System.Collections.Immutable.ImmutableArray searchPaths, string? baseDirectory) -> void Microsoft.CodeAnalysis.SourceFileResolver.SourceFileResolver(System.Collections.Immutable.ImmutableArray searchPaths, string? baseDirectory, System.Collections.Immutable.ImmutableArray> pathMap) -> void +Microsoft.CodeAnalysis.SourceProductionContext +Microsoft.CodeAnalysis.SourceProductionContext.AddSource(string! hintName, Microsoft.CodeAnalysis.Text.SourceText! sourceText) -> void +Microsoft.CodeAnalysis.SourceProductionContext.AddSource(string! hintName, string! source) -> void +Microsoft.CodeAnalysis.SourceProductionContext.CancellationToken.get -> System.Threading.CancellationToken +Microsoft.CodeAnalysis.SourceProductionContext.ReportDiagnostic(Microsoft.CodeAnalysis.Diagnostic! diagnostic) -> void +Microsoft.CodeAnalysis.SourceProductionContext.SourceProductionContext() -> void Microsoft.CodeAnalysis.SourceReferenceResolver Microsoft.CodeAnalysis.SourceReferenceResolver.SourceReferenceResolver() -> void Microsoft.CodeAnalysis.SpecialType @@ -2368,6 +2519,7 @@ Microsoft.CodeAnalysis.SymbolDisplayMemberOptions.IncludeType = 1 -> Microsoft.C Microsoft.CodeAnalysis.SymbolDisplayMemberOptions.None = 0 -> Microsoft.CodeAnalysis.SymbolDisplayMemberOptions Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions.AllowDefaultLiteral = 128 -> Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions +Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions.CollapseTupleTypes = 512 -> Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers = 2 -> Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions.ExpandNullable = 32 -> Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions.IncludeNotNullableReferenceTypeModifier = 256 -> Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions @@ -2417,6 +2569,8 @@ Microsoft.CodeAnalysis.SymbolDisplayPartKind.ParameterName = 19 -> Microsoft.Cod Microsoft.CodeAnalysis.SymbolDisplayPartKind.PropertyName = 20 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind Microsoft.CodeAnalysis.SymbolDisplayPartKind.Punctuation = 21 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind Microsoft.CodeAnalysis.SymbolDisplayPartKind.RangeVariableName = 27 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind +Microsoft.CodeAnalysis.SymbolDisplayPartKind.RecordClassName = 31 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind +Microsoft.CodeAnalysis.SymbolDisplayPartKind.RecordStructName = 32 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind Microsoft.CodeAnalysis.SymbolDisplayPartKind.Space = 22 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind Microsoft.CodeAnalysis.SymbolDisplayPartKind.StringLiteral = 13 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind Microsoft.CodeAnalysis.SymbolDisplayPartKind.StructName = 23 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind @@ -2478,6 +2632,7 @@ Microsoft.CodeAnalysis.SyntaxAnnotation.Kind.get -> string? Microsoft.CodeAnalysis.SyntaxAnnotation.SyntaxAnnotation() -> void Microsoft.CodeAnalysis.SyntaxAnnotation.SyntaxAnnotation(string? kind) -> void Microsoft.CodeAnalysis.SyntaxAnnotation.SyntaxAnnotation(string? kind, string? data) -> void +Microsoft.CodeAnalysis.SyntaxContextReceiverCreator Microsoft.CodeAnalysis.SyntaxList Microsoft.CodeAnalysis.SyntaxList.Add(TNode! node) -> Microsoft.CodeAnalysis.SyntaxList Microsoft.CodeAnalysis.SyntaxList.AddRange(System.Collections.Generic.IEnumerable! nodes) -> Microsoft.CodeAnalysis.SyntaxList @@ -2569,7 +2724,8 @@ Microsoft.CodeAnalysis.SyntaxNode.HasLeadingTrivia.get -> bool Microsoft.CodeAnalysis.SyntaxNode.HasStructuredTrivia.get -> bool Microsoft.CodeAnalysis.SyntaxNode.HasTrailingTrivia.get -> bool Microsoft.CodeAnalysis.SyntaxNode.IsEquivalentTo(Microsoft.CodeAnalysis.SyntaxNode! node, bool topLevel = false) -> bool -Microsoft.CodeAnalysis.SyntaxNode.IsEquivalentTo(Microsoft.CodeAnalysis.SyntaxNode! other) -> bool +Microsoft.CodeAnalysis.SyntaxNode.IsEquivalentTo(Microsoft.CodeAnalysis.SyntaxNode? other) -> bool +Microsoft.CodeAnalysis.SyntaxNode.IsIncrementallyIdenticalTo(Microsoft.CodeAnalysis.SyntaxNode? other) -> bool Microsoft.CodeAnalysis.SyntaxNode.IsMissing.get -> bool Microsoft.CodeAnalysis.SyntaxNode.IsPartOfStructuredTrivia() -> bool Microsoft.CodeAnalysis.SyntaxNode.IsStructuredTrivia.get -> bool @@ -2602,6 +2758,7 @@ Microsoft.CodeAnalysis.SyntaxNodeOrToken.HasAnnotations(System.Collections.Gener Microsoft.CodeAnalysis.SyntaxNodeOrToken.HasLeadingTrivia.get -> bool Microsoft.CodeAnalysis.SyntaxNodeOrToken.HasTrailingTrivia.get -> bool Microsoft.CodeAnalysis.SyntaxNodeOrToken.IsEquivalentTo(Microsoft.CodeAnalysis.SyntaxNodeOrToken other) -> bool +Microsoft.CodeAnalysis.SyntaxNodeOrToken.IsIncrementallyIdenticalTo(Microsoft.CodeAnalysis.SyntaxNodeOrToken other) -> bool Microsoft.CodeAnalysis.SyntaxNodeOrToken.IsMissing.get -> bool Microsoft.CodeAnalysis.SyntaxNodeOrToken.IsNode.get -> bool Microsoft.CodeAnalysis.SyntaxNodeOrToken.IsToken.get -> bool @@ -2686,6 +2843,7 @@ Microsoft.CodeAnalysis.SyntaxToken.HasLeadingTrivia.get -> bool Microsoft.CodeAnalysis.SyntaxToken.HasStructuredTrivia.get -> bool Microsoft.CodeAnalysis.SyntaxToken.HasTrailingTrivia.get -> bool Microsoft.CodeAnalysis.SyntaxToken.IsEquivalentTo(Microsoft.CodeAnalysis.SyntaxToken token) -> bool +Microsoft.CodeAnalysis.SyntaxToken.IsIncrementallyIdenticalTo(Microsoft.CodeAnalysis.SyntaxToken token) -> bool Microsoft.CodeAnalysis.SyntaxToken.IsMissing.get -> bool Microsoft.CodeAnalysis.SyntaxToken.IsPartOfStructuredTrivia() -> bool Microsoft.CodeAnalysis.SyntaxToken.Language.get -> string! @@ -2830,6 +2988,9 @@ Microsoft.CodeAnalysis.SyntaxTriviaList.SyntaxTriviaList(params Microsoft.CodeAn Microsoft.CodeAnalysis.SyntaxTriviaList.SyntaxTriviaList(System.Collections.Generic.IEnumerable? trivias) -> void Microsoft.CodeAnalysis.SyntaxTriviaList.this[int index].get -> Microsoft.CodeAnalysis.SyntaxTrivia Microsoft.CodeAnalysis.SyntaxTriviaList.ToFullString() -> string! +Microsoft.CodeAnalysis.SyntaxValueProvider +Microsoft.CodeAnalysis.SyntaxValueProvider.CreateSyntaxProvider(System.Func! predicate, System.Func! transform) -> Microsoft.CodeAnalysis.IncrementalValuesProvider +Microsoft.CodeAnalysis.SyntaxValueProvider.SyntaxValueProvider() -> void Microsoft.CodeAnalysis.SyntaxWalker Microsoft.CodeAnalysis.SyntaxWalker.Depth.get -> Microsoft.CodeAnalysis.SyntaxWalkerDepth Microsoft.CodeAnalysis.SyntaxWalker.SyntaxWalker(Microsoft.CodeAnalysis.SyntaxWalkerDepth depth = Microsoft.CodeAnalysis.SyntaxWalkerDepth.Node) -> void @@ -2971,6 +3132,8 @@ Microsoft.CodeAnalysis.VarianceKind.In = 2 -> Microsoft.CodeAnalysis.VarianceKin Microsoft.CodeAnalysis.VarianceKind.None = 0 -> Microsoft.CodeAnalysis.VarianceKind Microsoft.CodeAnalysis.VarianceKind.Out = 1 -> Microsoft.CodeAnalysis.VarianceKind Microsoft.CodeAnalysis.WellKnownDiagnosticTags +Microsoft.CodeAnalysis.WellKnownGeneratorInputs +Microsoft.CodeAnalysis.WellKnownGeneratorOutputs Microsoft.CodeAnalysis.WellKnownMemberNames Microsoft.CodeAnalysis.XmlFileResolver Microsoft.CodeAnalysis.XmlFileResolver.BaseDirectory.get -> string? @@ -2979,7 +3142,6 @@ Microsoft.CodeAnalysis.XmlReferenceResolver Microsoft.CodeAnalysis.XmlReferenceResolver.XmlReferenceResolver() -> void override abstract Microsoft.CodeAnalysis.CompilationOptions.Equals(object? obj) -> bool override abstract Microsoft.CodeAnalysis.CompilationOptions.GetHashCode() -> int -override abstract Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool override abstract Microsoft.CodeAnalysis.Diagnostic.GetHashCode() -> int override abstract Microsoft.CodeAnalysis.DocumentationProvider.Equals(object? obj) -> bool override abstract Microsoft.CodeAnalysis.DocumentationProvider.GetHashCode() -> int @@ -3022,6 +3184,8 @@ override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.FullPath.get - override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetAnalyzers(string! language) -> System.Collections.Immutable.ImmutableArray override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetAnalyzersForAllLanguages() -> System.Collections.Immutable.ImmutableArray override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGenerators() -> System.Collections.Immutable.ImmutableArray +override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGenerators(string! language) -> System.Collections.Immutable.ImmutableArray +override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGeneratorsForAllLanguages() -> System.Collections.Immutable.ImmutableArray override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetHashCode() -> int override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.Id.get -> object! override Microsoft.CodeAnalysis.Diagnostics.AnalyzerImageReference.Display.get -> string! @@ -3047,6 +3211,9 @@ override Microsoft.CodeAnalysis.FileLinePositionSpan.GetHashCode() -> int override Microsoft.CodeAnalysis.FileLinePositionSpan.ToString() -> string! override Microsoft.CodeAnalysis.FlowAnalysis.CaptureId.Equals(object? obj) -> bool override Microsoft.CodeAnalysis.FlowAnalysis.CaptureId.GetHashCode() -> int +override Microsoft.CodeAnalysis.LineMapping.Equals(object? obj) -> bool +override Microsoft.CodeAnalysis.LineMapping.GetHashCode() -> int +override Microsoft.CodeAnalysis.LineMapping.ToString() -> string? override Microsoft.CodeAnalysis.Location.ToString() -> string! override Microsoft.CodeAnalysis.MetadataReferenceProperties.Equals(object? obj) -> bool override Microsoft.CodeAnalysis.MetadataReferenceProperties.GetHashCode() -> int @@ -3056,6 +3223,8 @@ override Microsoft.CodeAnalysis.NullabilityInfo.Equals(object? other) -> bool override Microsoft.CodeAnalysis.NullabilityInfo.GetHashCode() -> int override Microsoft.CodeAnalysis.Operations.OperationWalker.DefaultVisit(Microsoft.CodeAnalysis.IOperation! operation) -> void override Microsoft.CodeAnalysis.Operations.OperationWalker.Visit(Microsoft.CodeAnalysis.IOperation? operation) -> void +override Microsoft.CodeAnalysis.Operations.OperationWalker.DefaultVisit(Microsoft.CodeAnalysis.IOperation! operation, TArgument argument) -> object? +override Microsoft.CodeAnalysis.Operations.OperationWalker.Visit(Microsoft.CodeAnalysis.IOperation? operation, TArgument argument) -> object? override Microsoft.CodeAnalysis.Optional.ToString() -> string! override Microsoft.CodeAnalysis.PortableExecutableReference.Display.get -> string? override Microsoft.CodeAnalysis.PreprocessingSymbolInfo.Equals(object? obj) -> bool @@ -3127,6 +3296,7 @@ override Microsoft.CodeAnalysis.Text.TextChange.GetHashCode() -> int override Microsoft.CodeAnalysis.Text.TextChange.ToString() -> string! override Microsoft.CodeAnalysis.Text.TextChangeRange.Equals(object? obj) -> bool override Microsoft.CodeAnalysis.Text.TextChangeRange.GetHashCode() -> int +override Microsoft.CodeAnalysis.Text.TextChangeRange.ToString() -> string! override Microsoft.CodeAnalysis.Text.TextLine.Equals(object? obj) -> bool override Microsoft.CodeAnalysis.Text.TextLine.GetHashCode() -> int override Microsoft.CodeAnalysis.Text.TextLine.ToString() -> string! @@ -3152,6 +3322,8 @@ override sealed Microsoft.CodeAnalysis.Diagnostics.DiagnosticSuppressor.Supporte override sealed Microsoft.CodeAnalysis.LocalizableString.Equals(object? other) -> bool override sealed Microsoft.CodeAnalysis.LocalizableString.GetHashCode() -> int override sealed Microsoft.CodeAnalysis.LocalizableString.ToString() -> string! +readonly Microsoft.CodeAnalysis.GeneratorDriverOptions.DisabledOutputs -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind +readonly Microsoft.CodeAnalysis.GeneratorDriverOptions.TrackIncrementalGeneratorSteps -> bool static Microsoft.CodeAnalysis.AnalyzerConfig.Parse(Microsoft.CodeAnalysis.Text.SourceText! text, string? pathToFile) -> Microsoft.CodeAnalysis.AnalyzerConfig! static Microsoft.CodeAnalysis.AnalyzerConfig.Parse(string! text, string? pathToFile) -> Microsoft.CodeAnalysis.AnalyzerConfig! static Microsoft.CodeAnalysis.AnalyzerConfigSet.Create(TList analyzerConfigs) -> Microsoft.CodeAnalysis.AnalyzerConfigSet! @@ -3179,9 +3351,11 @@ static Microsoft.CodeAnalysis.AssemblyMetadata.CreateFromImage(System.Collection static Microsoft.CodeAnalysis.AssemblyMetadata.CreateFromStream(System.IO.Stream! peStream, bool leaveOpen = false) -> Microsoft.CodeAnalysis.AssemblyMetadata! static Microsoft.CodeAnalysis.AssemblyMetadata.CreateFromStream(System.IO.Stream! peStream, System.Reflection.PortableExecutable.PEStreamOptions options) -> Microsoft.CodeAnalysis.AssemblyMetadata! static Microsoft.CodeAnalysis.CaseInsensitiveComparison.Compare(string! left, string! right) -> int +static Microsoft.CodeAnalysis.CaseInsensitiveComparison.Compare(System.ReadOnlySpan left, System.ReadOnlySpan right) -> int static Microsoft.CodeAnalysis.CaseInsensitiveComparison.Comparer.get -> System.StringComparer! static Microsoft.CodeAnalysis.CaseInsensitiveComparison.EndsWith(string! value, string! possibleEnd) -> bool static Microsoft.CodeAnalysis.CaseInsensitiveComparison.Equals(string! left, string! right) -> bool +static Microsoft.CodeAnalysis.CaseInsensitiveComparison.Equals(System.ReadOnlySpan left, System.ReadOnlySpan right) -> bool static Microsoft.CodeAnalysis.CaseInsensitiveComparison.GetHashCode(string! value) -> int static Microsoft.CodeAnalysis.CaseInsensitiveComparison.StartsWith(string! value, string! possibleStart) -> bool static Microsoft.CodeAnalysis.CaseInsensitiveComparison.ToLower(char c) -> char @@ -3227,6 +3401,10 @@ static Microsoft.CodeAnalysis.Emit.EmitBaseline.CreateInitialBaseline(Microsoft. static Microsoft.CodeAnalysis.Emit.EmitBaseline.CreateInitialBaseline(Microsoft.CodeAnalysis.ModuleMetadata! module, System.Func! debugInformationProvider, System.Func! localSignatureProvider, bool hasPortableDebugInformation) -> Microsoft.CodeAnalysis.Emit.EmitBaseline! static Microsoft.CodeAnalysis.Emit.EmitOptions.operator !=(Microsoft.CodeAnalysis.Emit.EmitOptions? left, Microsoft.CodeAnalysis.Emit.EmitOptions? right) -> bool static Microsoft.CodeAnalysis.Emit.EmitOptions.operator ==(Microsoft.CodeAnalysis.Emit.EmitOptions? left, Microsoft.CodeAnalysis.Emit.EmitOptions? right) -> bool +static Microsoft.CodeAnalysis.Emit.SemanticEdit.operator !=(Microsoft.CodeAnalysis.Emit.SemanticEdit left, Microsoft.CodeAnalysis.Emit.SemanticEdit right) -> bool +static Microsoft.CodeAnalysis.Emit.SemanticEdit.operator ==(Microsoft.CodeAnalysis.Emit.SemanticEdit left, Microsoft.CodeAnalysis.Emit.SemanticEdit right) -> bool +static Microsoft.CodeAnalysis.FileLinePositionSpan.operator !=(Microsoft.CodeAnalysis.FileLinePositionSpan left, Microsoft.CodeAnalysis.FileLinePositionSpan right) -> bool +static Microsoft.CodeAnalysis.FileLinePositionSpan.operator ==(Microsoft.CodeAnalysis.FileLinePositionSpan left, Microsoft.CodeAnalysis.FileLinePositionSpan right) -> bool static Microsoft.CodeAnalysis.FileSystemExtensions.Emit(this Microsoft.CodeAnalysis.Compilation! compilation, string! outputPath, string? pdbPath = null, string? xmlDocPath = null, string? win32ResourcesPath = null, System.Collections.Generic.IEnumerable? manifestResources = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Emit.EmitResult! static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph.Create(Microsoft.CodeAnalysis.Operations.IBlockOperation! body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph.Create(Microsoft.CodeAnalysis.Operations.IConstructorBodyOperation! constructorBody, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! @@ -3237,7 +3415,25 @@ static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph.Create(Microsoft.Cod static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph.Create(Microsoft.CodeAnalysis.SyntaxNode! node, Microsoft.CodeAnalysis.SemanticModel! semanticModel, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph? static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraphExtensions.GetAnonymousFunctionControlFlowGraphInScope(this Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! controlFlowGraph, Microsoft.CodeAnalysis.FlowAnalysis.IFlowAnonymousFunctionOperation! anonymousFunction, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! static Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraphExtensions.GetLocalFunctionControlFlowGraphInScope(this Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! controlFlowGraph, Microsoft.CodeAnalysis.IMethodSymbol! localFunction, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! +static Microsoft.CodeAnalysis.GeneratorExtensions.AsSourceGenerator(this Microsoft.CodeAnalysis.IIncrementalGenerator! incrementalGenerator) -> Microsoft.CodeAnalysis.ISourceGenerator! +static Microsoft.CodeAnalysis.GeneratorExtensions.GetGeneratorType(this Microsoft.CodeAnalysis.ISourceGenerator! generator) -> System.Type! +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Collect(this Microsoft.CodeAnalysis.IncrementalValuesProvider source) -> Microsoft.CodeAnalysis.IncrementalValueProvider> +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Combine(this Microsoft.CodeAnalysis.IncrementalValueProvider provider1, Microsoft.CodeAnalysis.IncrementalValueProvider provider2) -> Microsoft.CodeAnalysis.IncrementalValueProvider<(TLeft Left, TRight Right)> +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Combine(this Microsoft.CodeAnalysis.IncrementalValuesProvider provider1, Microsoft.CodeAnalysis.IncrementalValueProvider provider2) -> Microsoft.CodeAnalysis.IncrementalValuesProvider<(TLeft Left, TRight Right)> +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Select(this Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Func! selector) -> Microsoft.CodeAnalysis.IncrementalValueProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Select(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Func! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.SelectMany(this Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Func!>! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.SelectMany(this Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Func>! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.SelectMany(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Func!>! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.SelectMany(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Func>! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Where(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Func! predicate) -> Microsoft.CodeAnalysis.IncrementalValuesProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.WithComparer(this Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Collections.Generic.IEqualityComparer! comparer) -> Microsoft.CodeAnalysis.IncrementalValueProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.WithComparer(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Collections.Generic.IEqualityComparer! comparer) -> Microsoft.CodeAnalysis.IncrementalValuesProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.WithTrackingName(this Microsoft.CodeAnalysis.IncrementalValueProvider source, string! name) -> Microsoft.CodeAnalysis.IncrementalValueProvider +static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.WithTrackingName(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, string! name) -> Microsoft.CodeAnalysis.IncrementalValuesProvider static Microsoft.CodeAnalysis.ISymbolExtensions.GetConstructedReducedFrom(this Microsoft.CodeAnalysis.IMethodSymbol! method) -> Microsoft.CodeAnalysis.IMethodSymbol? +static Microsoft.CodeAnalysis.LineMapping.operator !=(Microsoft.CodeAnalysis.LineMapping left, Microsoft.CodeAnalysis.LineMapping right) -> bool +static Microsoft.CodeAnalysis.LineMapping.operator ==(Microsoft.CodeAnalysis.LineMapping left, Microsoft.CodeAnalysis.LineMapping right) -> bool static Microsoft.CodeAnalysis.LocalizableString.explicit operator string?(Microsoft.CodeAnalysis.LocalizableString! localizableResource) -> string? static Microsoft.CodeAnalysis.LocalizableString.implicit operator Microsoft.CodeAnalysis.LocalizableString!(string? fixedResource) -> Microsoft.CodeAnalysis.LocalizableString! static Microsoft.CodeAnalysis.Location.Create(Microsoft.CodeAnalysis.SyntaxTree! syntaxTree, Microsoft.CodeAnalysis.Text.TextSpan textSpan) -> Microsoft.CodeAnalysis.Location! @@ -3292,6 +3488,7 @@ static Microsoft.CodeAnalysis.Operations.OperationExtensions.GetArgumentRefKind( static Microsoft.CodeAnalysis.Operations.OperationExtensions.GetCorrespondingOperation(this Microsoft.CodeAnalysis.Operations.IBranchOperation! operation) -> Microsoft.CodeAnalysis.IOperation? static Microsoft.CodeAnalysis.Operations.OperationExtensions.GetDeclaredVariables(this Microsoft.CodeAnalysis.Operations.IVariableDeclarationGroupOperation! declarationGroup) -> System.Collections.Immutable.ImmutableArray static Microsoft.CodeAnalysis.Operations.OperationExtensions.GetDeclaredVariables(this Microsoft.CodeAnalysis.Operations.IVariableDeclarationOperation! declaration) -> System.Collections.Immutable.ImmutableArray +static Microsoft.CodeAnalysis.Operations.OperationExtensions.GetFunctionPointerSignature(this Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation! functionPointer) -> Microsoft.CodeAnalysis.IMethodSymbol! static Microsoft.CodeAnalysis.Operations.OperationExtensions.GetVariableInitializer(this Microsoft.CodeAnalysis.Operations.IVariableDeclaratorOperation! declarationOperation) -> Microsoft.CodeAnalysis.Operations.IVariableInitializerOperation? static Microsoft.CodeAnalysis.Optional.implicit operator Microsoft.CodeAnalysis.Optional(T value) -> Microsoft.CodeAnalysis.Optional static Microsoft.CodeAnalysis.ParseOptions.operator !=(Microsoft.CodeAnalysis.ParseOptions? left, Microsoft.CodeAnalysis.ParseOptions? right) -> bool @@ -3428,6 +3625,8 @@ virtual Microsoft.CodeAnalysis.Diagnostics.AnalysisContext.RegisterOperationBloc virtual Microsoft.CodeAnalysis.Diagnostics.AnalysisContext.RegisterSymbolStartAction(System.Action! action, Microsoft.CodeAnalysis.SymbolKind symbolKind) -> void virtual Microsoft.CodeAnalysis.Diagnostics.AnalyzerReference.Display.get -> string! virtual Microsoft.CodeAnalysis.Diagnostics.AnalyzerReference.GetGenerators() -> System.Collections.Immutable.ImmutableArray +virtual Microsoft.CodeAnalysis.Diagnostics.AnalyzerReference.GetGenerators(string! language) -> System.Collections.Immutable.ImmutableArray +virtual Microsoft.CodeAnalysis.Diagnostics.AnalyzerReference.GetGeneratorsForAllLanguages() -> System.Collections.Immutable.ImmutableArray virtual Microsoft.CodeAnalysis.Diagnostics.CompilationStartAnalysisContext.RegisterAdditionalFileAction(System.Action! action) -> void virtual Microsoft.CodeAnalysis.Diagnostics.CompilationStartAnalysisContext.RegisterOperationAction(System.Action! action, System.Collections.Immutable.ImmutableArray operationKinds) -> void virtual Microsoft.CodeAnalysis.Diagnostics.CompilationStartAnalysisContext.RegisterOperationBlockAction(System.Action! action) -> void @@ -3491,9 +3690,15 @@ virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitFlowCaptureRefer virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitForEachLoop(Microsoft.CodeAnalysis.Operations.IForEachLoopOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitForLoop(Microsoft.CodeAnalysis.Operations.IForLoopOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitForToLoop(Microsoft.CodeAnalysis.Operations.IForToLoopOperation! operation) -> void +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitFunctionPointerInvocation(Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation! operation) -> void +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitImplicitIndexerReference(Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitIncrementOrDecrement(Microsoft.CodeAnalysis.Operations.IIncrementOrDecrementOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInstanceReference(Microsoft.CodeAnalysis.Operations.IInstanceReferenceOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedString(Microsoft.CodeAnalysis.Operations.IInterpolatedStringOperation! operation) -> void +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringAddition(Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation! operation) -> void +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringAppend(Microsoft.CodeAnalysis.Operations.IInterpolatedStringAppendOperation! operation) -> void +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringHandlerArgumentPlaceholder(Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation! operation) -> void +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringHandlerCreation(Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringText(Microsoft.CodeAnalysis.Operations.IInterpolatedStringTextOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolation(Microsoft.CodeAnalysis.Operations.IInterpolationOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInvalid(Microsoft.CodeAnalysis.Operations.IInvalidOperation! operation) -> void @@ -3502,6 +3707,7 @@ virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitIsNull(Microsoft virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitIsPattern(Microsoft.CodeAnalysis.Operations.IIsPatternOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitIsType(Microsoft.CodeAnalysis.Operations.IIsTypeOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitLabeled(Microsoft.CodeAnalysis.Operations.ILabeledOperation! operation) -> void +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitListPattern(Microsoft.CodeAnalysis.Operations.IListPatternOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitLiteral(Microsoft.CodeAnalysis.Operations.ILiteralOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitLocalFunction(Microsoft.CodeAnalysis.Operations.ILocalFunctionOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitLocalReference(Microsoft.CodeAnalysis.Operations.ILocalReferenceOperation! operation) -> void @@ -3533,6 +3739,7 @@ virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitReturn(Microsoft virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSimpleAssignment(Microsoft.CodeAnalysis.Operations.ISimpleAssignmentOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSingleValueCaseClause(Microsoft.CodeAnalysis.Operations.ISingleValueCaseClauseOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSizeOf(Microsoft.CodeAnalysis.Operations.ISizeOfOperation! operation) -> void +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSlicePattern(Microsoft.CodeAnalysis.Operations.ISlicePatternOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitStaticLocalInitializationSemaphore(Microsoft.CodeAnalysis.FlowAnalysis.IStaticLocalInitializationSemaphoreOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitStop(Microsoft.CodeAnalysis.Operations.IStopOperation! operation) -> void virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSwitch(Microsoft.CodeAnalysis.Operations.ISwitchOperation! operation) -> void @@ -3607,9 +3814,15 @@ virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.V virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitForEachLoop(Microsoft.CodeAnalysis.Operations.IForEachLoopOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitForLoop(Microsoft.CodeAnalysis.Operations.IForLoopOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitForToLoop(Microsoft.CodeAnalysis.Operations.IForToLoopOperation! operation, TArgument argument) -> TResult? +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitFunctionPointerInvocation(Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation! operation, TArgument argument) -> TResult? +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitImplicitIndexerReference(Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitIncrementOrDecrement(Microsoft.CodeAnalysis.Operations.IIncrementOrDecrementOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInstanceReference(Microsoft.CodeAnalysis.Operations.IInstanceReferenceOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedString(Microsoft.CodeAnalysis.Operations.IInterpolatedStringOperation! operation, TArgument argument) -> TResult? +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringAddition(Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation! operation, TArgument argument) -> TResult? +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringAppend(Microsoft.CodeAnalysis.Operations.IInterpolatedStringAppendOperation! operation, TArgument argument) -> TResult? +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringHandlerArgumentPlaceholder(Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation! operation, TArgument argument) -> TResult? +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringHandlerCreation(Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringText(Microsoft.CodeAnalysis.Operations.IInterpolatedStringTextOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolation(Microsoft.CodeAnalysis.Operations.IInterpolationOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInvalid(Microsoft.CodeAnalysis.Operations.IInvalidOperation! operation, TArgument argument) -> TResult? @@ -3618,6 +3831,7 @@ virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.V virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitIsPattern(Microsoft.CodeAnalysis.Operations.IIsPatternOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitIsType(Microsoft.CodeAnalysis.Operations.IIsTypeOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitLabeled(Microsoft.CodeAnalysis.Operations.ILabeledOperation! operation, TArgument argument) -> TResult? +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitListPattern(Microsoft.CodeAnalysis.Operations.IListPatternOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitLiteral(Microsoft.CodeAnalysis.Operations.ILiteralOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitLocalFunction(Microsoft.CodeAnalysis.Operations.ILocalFunctionOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitLocalReference(Microsoft.CodeAnalysis.Operations.ILocalReferenceOperation! operation, TArgument argument) -> TResult? @@ -3649,6 +3863,7 @@ virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.V virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSimpleAssignment(Microsoft.CodeAnalysis.Operations.ISimpleAssignmentOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSingleValueCaseClause(Microsoft.CodeAnalysis.Operations.ISingleValueCaseClauseOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSizeOf(Microsoft.CodeAnalysis.Operations.ISizeOfOperation! operation, TArgument argument) -> TResult? +virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSlicePattern(Microsoft.CodeAnalysis.Operations.ISlicePatternOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitStaticLocalInitializationSemaphore(Microsoft.CodeAnalysis.FlowAnalysis.IStaticLocalInitializationSemaphoreOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitStop(Microsoft.CodeAnalysis.Operations.IStopOperation! operation, TArgument argument) -> TResult? virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSwitch(Microsoft.CodeAnalysis.Operations.ISwitchOperation! operation, TArgument argument) -> TResult? diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index ad76fcb80cd4d..745c6f1fb06c3 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,220 +1,30 @@ -*REMOVED*Microsoft.CodeAnalysis.SyntaxNode.IsEquivalentTo(Microsoft.CodeAnalysis.SyntaxNode! other) -> bool -abstract Microsoft.CodeAnalysis.SyntaxTree.GetLineMappings(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! -const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.AdditionalTexts = "AdditionalTexts" -> string! -const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.AnalyzerConfigOptions = "AnalyzerConfigOptions" -> string! -const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.Compilation = "Compilation" -> string! -const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.MetadataReferences = "MetadataReferences" -> string! -const Microsoft.CodeAnalysis.WellKnownGeneratorInputs.ParseOptions = "ParseOptions" -> string! -const Microsoft.CodeAnalysis.WellKnownGeneratorOutputs.ImplementationSourceOutput = "ImplementationSourceOutput" -> string! -const Microsoft.CodeAnalysis.WellKnownGeneratorOutputs.SourceOutput = "SourceOutput" -> string! -const Microsoft.CodeAnalysis.WellKnownMemberNames.PrintMembersMethodName = "PrintMembers" -> string! -Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! +*REMOVED*override abstract Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool Microsoft.CodeAnalysis.Compilation.GetTypesByMetadataName(string! fullyQualifiedMetadataName) -> System.Collections.Immutable.ImmutableArray -Microsoft.CodeAnalysis.Emit.EmitDifferenceResult.ChangedTypes.get -> System.Collections.Immutable.ImmutableArray -Microsoft.CodeAnalysis.Emit.EmitDifferenceResult.UpdatedMethods.get -> System.Collections.Immutable.ImmutableArray -Microsoft.CodeAnalysis.Emit.SemanticEditKind.Replace = 4 -> Microsoft.CodeAnalysis.Emit.SemanticEditKind -Microsoft.CodeAnalysis.FlowAnalysis.IFlowCaptureReferenceOperation.IsInitialization.get -> bool -Microsoft.CodeAnalysis.GeneratorAttribute.GeneratorAttribute(string! firstLanguage, params string![]! additionalLanguages) -> void -Microsoft.CodeAnalysis.GeneratorAttribute.Languages.get -> string![]! -Microsoft.CodeAnalysis.GeneratorDriver.ReplaceAdditionalText(Microsoft.CodeAnalysis.AdditionalText! oldText, Microsoft.CodeAnalysis.AdditionalText! newText) -> Microsoft.CodeAnalysis.GeneratorDriver! -Microsoft.CodeAnalysis.GeneratorDriver.ReplaceAdditionalTexts(System.Collections.Immutable.ImmutableArray newTexts) -> Microsoft.CodeAnalysis.GeneratorDriver! -Microsoft.CodeAnalysis.GeneratorDriver.WithUpdatedAnalyzerConfigOptions(Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider! newOptions) -> Microsoft.CodeAnalysis.GeneratorDriver! -Microsoft.CodeAnalysis.GeneratorDriver.WithUpdatedParseOptions(Microsoft.CodeAnalysis.ParseOptions! newOptions) -> Microsoft.CodeAnalysis.GeneratorDriver! -Microsoft.CodeAnalysis.GeneratorDriverOptions -Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions() -> void -Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions(Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind disabledOutputs) -> void -Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions(Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind disabledOutputs, bool trackIncrementalGeneratorSteps) -> void -Microsoft.CodeAnalysis.GeneratorExtensions -Microsoft.CodeAnalysis.GeneratorRunResult.TrackedOutputSteps.get -> System.Collections.Immutable.ImmutableDictionary>! -Microsoft.CodeAnalysis.GeneratorRunResult.TrackedSteps.get -> System.Collections.Immutable.ImmutableDictionary>! -Microsoft.CodeAnalysis.IFieldSymbol.FixedSize.get -> int -Microsoft.CodeAnalysis.IFieldSymbol.IsExplicitlyNamedTupleElement.get -> bool -Microsoft.CodeAnalysis.GeneratorExecutionContext.SyntaxContextReceiver.get -> Microsoft.CodeAnalysis.ISyntaxContextReceiver? -Microsoft.CodeAnalysis.GeneratorInitializationContext.RegisterForSyntaxNotifications(Microsoft.CodeAnalysis.SyntaxContextReceiverCreator! receiverCreator) -> void -Microsoft.CodeAnalysis.GeneratorSyntaxContext -Microsoft.CodeAnalysis.GeneratorSyntaxContext.GeneratorSyntaxContext() -> void -Microsoft.CodeAnalysis.GeneratorSyntaxContext.Node.get -> Microsoft.CodeAnalysis.SyntaxNode! -Microsoft.CodeAnalysis.GeneratorSyntaxContext.SemanticModel.get -> Microsoft.CodeAnalysis.SemanticModel! -Microsoft.CodeAnalysis.IIncrementalGenerator -Microsoft.CodeAnalysis.IIncrementalGenerator.Initialize(Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext context) -> void -Microsoft.CodeAnalysis.IMethodSymbol.IsPartialDefinition.get -> bool -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.AdditionalTextsProvider.get -> Microsoft.CodeAnalysis.IncrementalValuesProvider -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.AnalyzerConfigOptionsProvider.get -> Microsoft.CodeAnalysis.IncrementalValueProvider -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.CompilationProvider.get -> Microsoft.CodeAnalysis.IncrementalValueProvider -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.IncrementalGeneratorInitializationContext() -> void -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.MetadataReferencesProvider.get -> Microsoft.CodeAnalysis.IncrementalValueProvider -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.ParseOptionsProvider.get -> Microsoft.CodeAnalysis.IncrementalValueProvider -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterImplementationSourceOutput(Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Action! action) -> void -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterImplementationSourceOutput(Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Action! action) -> void -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterPostInitializationOutput(System.Action! callback) -> void -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterSourceOutput(Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Action! action) -> void -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterSourceOutput(Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Action! action) -> void -Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.SyntaxProvider.get -> Microsoft.CodeAnalysis.SyntaxValueProvider -Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind -Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.Implementation = 4 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind -Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.None = 0 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind -Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.PostInit = 2 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind -Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.Source = 1 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind -Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext -Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.AddSource(string! hintName, Microsoft.CodeAnalysis.Text.SourceText! sourceText) -> void -Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.AddSource(string! hintName, string! source) -> void -Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.CancellationToken.get -> System.Threading.CancellationToken -Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.IncrementalGeneratorPostInitializationContext() -> void -Microsoft.CodeAnalysis.IncrementalGeneratorRunStep -Microsoft.CodeAnalysis.IncrementalGeneratorRunStep.ElapsedTime.get -> System.TimeSpan -Microsoft.CodeAnalysis.IncrementalGeneratorRunStep.Inputs.get -> System.Collections.Immutable.ImmutableArray<(Microsoft.CodeAnalysis.IncrementalGeneratorRunStep! Source, int OutputIndex)> -Microsoft.CodeAnalysis.IncrementalGeneratorRunStep.Name.get -> string? -Microsoft.CodeAnalysis.IncrementalGeneratorRunStep.Outputs.get -> System.Collections.Immutable.ImmutableArray<(object! Value, Microsoft.CodeAnalysis.IncrementalStepRunReason Reason)> -Microsoft.CodeAnalysis.IncrementalStepRunReason -Microsoft.CodeAnalysis.IncrementalStepRunReason.Cached = 3 -> Microsoft.CodeAnalysis.IncrementalStepRunReason -Microsoft.CodeAnalysis.IncrementalStepRunReason.Modified = 1 -> Microsoft.CodeAnalysis.IncrementalStepRunReason -Microsoft.CodeAnalysis.IncrementalStepRunReason.New = 0 -> Microsoft.CodeAnalysis.IncrementalStepRunReason -Microsoft.CodeAnalysis.IncrementalStepRunReason.Removed = 4 -> Microsoft.CodeAnalysis.IncrementalStepRunReason -Microsoft.CodeAnalysis.IncrementalStepRunReason.Unchanged = 2 -> Microsoft.CodeAnalysis.IncrementalStepRunReason -Microsoft.CodeAnalysis.IncrementalValueProvider -Microsoft.CodeAnalysis.IncrementalValueProvider.IncrementalValueProvider() -> void -Microsoft.CodeAnalysis.IncrementalValueProviderExtensions -Microsoft.CodeAnalysis.IncrementalValuesProvider -Microsoft.CodeAnalysis.IncrementalValuesProvider.IncrementalValuesProvider() -> void -Microsoft.CodeAnalysis.IParameterSymbol.IsNullChecked.get -> bool -Microsoft.CodeAnalysis.ISymbol.MetadataToken.get -> int -Microsoft.CodeAnalysis.ISyntaxContextReceiver -Microsoft.CodeAnalysis.ISyntaxContextReceiver.OnVisitSyntaxNode(Microsoft.CodeAnalysis.GeneratorSyntaxContext context) -> void -Microsoft.CodeAnalysis.GeneratorInitializationContext.RegisterForPostInitialization(System.Action! callback) -> void -Microsoft.CodeAnalysis.GeneratorPostInitializationContext -Microsoft.CodeAnalysis.GeneratorPostInitializationContext.AddSource(string! hintName, Microsoft.CodeAnalysis.Text.SourceText! sourceText) -> void -Microsoft.CodeAnalysis.GeneratorPostInitializationContext.AddSource(string! hintName, string! source) -> void -Microsoft.CodeAnalysis.GeneratorPostInitializationContext.CancellationToken.get -> System.Threading.CancellationToken -Microsoft.CodeAnalysis.GeneratorPostInitializationContext.GeneratorPostInitializationContext() -> void -Microsoft.CodeAnalysis.IMethodSymbol.MethodImplementationFlags.get -> System.Reflection.MethodImplAttributes -Microsoft.CodeAnalysis.ITypeSymbol.IsRecord.get -> bool -Microsoft.CodeAnalysis.LineMapping -Microsoft.CodeAnalysis.LineMapping.CharacterOffset.get -> int? -Microsoft.CodeAnalysis.LineMapping.Equals(Microsoft.CodeAnalysis.LineMapping other) -> bool -Microsoft.CodeAnalysis.LineMapping.IsHidden.get -> bool -Microsoft.CodeAnalysis.LineMapping.LineMapping() -> void -Microsoft.CodeAnalysis.LineMapping.LineMapping(Microsoft.CodeAnalysis.Text.LinePositionSpan span, int? characterOffset, Microsoft.CodeAnalysis.FileLinePositionSpan mappedSpan) -> void -Microsoft.CodeAnalysis.LineMapping.MappedSpan.get -> Microsoft.CodeAnalysis.FileLinePositionSpan -Microsoft.CodeAnalysis.LineMapping.Span.get -> Microsoft.CodeAnalysis.Text.LinePositionSpan -Microsoft.CodeAnalysis.OperationKind.FunctionPointerInvocation = 120 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.OperationKind.ImplicitIndexerReference = 123 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation -Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation.Arguments.get -> System.Collections.Immutable.ImmutableArray -Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation.Target.get -> Microsoft.CodeAnalysis.IOperation! -Microsoft.CodeAnalysis.OperationKind.InterpolatedStringAddition = 115 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.OperationKind.InterpolatedStringAppendFormatted = 117 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.OperationKind.InterpolatedStringAppendInvalid = 118 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.OperationKind.InterpolatedStringAppendLiteral = 116 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.OperationKind.InterpolatedStringHandlerArgumentPlaceholder = 119 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.OperationKind.InterpolatedStringHandlerCreation = 114 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation -Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation.Argument.get -> Microsoft.CodeAnalysis.IOperation! -Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation.IndexerSymbol.get -> Microsoft.CodeAnalysis.ISymbol! -Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation.Instance.get -> Microsoft.CodeAnalysis.IOperation! -Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation.LengthSymbol.get -> Microsoft.CodeAnalysis.ISymbol! -Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation -Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation.Left.get -> Microsoft.CodeAnalysis.IOperation! -Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation.Right.get -> Microsoft.CodeAnalysis.IOperation! -Microsoft.CodeAnalysis.Operations.IInterpolatedStringAppendOperation -Microsoft.CodeAnalysis.Operations.IInterpolatedStringAppendOperation.AppendCall.get -> Microsoft.CodeAnalysis.IOperation! -Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation -Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation.ArgumentIndex.get -> int -Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation.PlaceholderKind.get -> Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind -Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation -Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation.Content.get -> Microsoft.CodeAnalysis.IOperation! -Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation.HandlerAppendCallsReturnBool.get -> bool -Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation.HandlerCreation.get -> Microsoft.CodeAnalysis.IOperation! -Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation.HandlerCreationHasSuccessParameter.get -> bool -Microsoft.CodeAnalysis.Operations.InstanceReferenceKind.InterpolatedStringHandler = 3 -> Microsoft.CodeAnalysis.Operations.InstanceReferenceKind -Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind -Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind.CallsiteArgument = 0 -> Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind -Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind.CallsiteReceiver = 1 -> Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind -Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument = 2 -> Microsoft.CodeAnalysis.Operations.InterpolatedStringArgumentPlaceholderKind -Microsoft.CodeAnalysis.OperationKind.ListPattern = 121 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.OperationKind.SlicePattern = 122 -> Microsoft.CodeAnalysis.OperationKind -Microsoft.CodeAnalysis.Operations.IListPatternOperation -Microsoft.CodeAnalysis.Operations.IListPatternOperation.DeclaredSymbol.get -> Microsoft.CodeAnalysis.ISymbol? -Microsoft.CodeAnalysis.Operations.IListPatternOperation.IndexerSymbol.get -> Microsoft.CodeAnalysis.ISymbol? -Microsoft.CodeAnalysis.Operations.IListPatternOperation.LengthSymbol.get -> Microsoft.CodeAnalysis.ISymbol? -Microsoft.CodeAnalysis.Operations.IListPatternOperation.Patterns.get -> System.Collections.Immutable.ImmutableArray -Microsoft.CodeAnalysis.Operations.ISlicePatternOperation -Microsoft.CodeAnalysis.Operations.ISlicePatternOperation.Pattern.get -> Microsoft.CodeAnalysis.Operations.IPatternOperation? -Microsoft.CodeAnalysis.Operations.ISlicePatternOperation.SliceSymbol.get -> Microsoft.CodeAnalysis.ISymbol? -Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions.CollapseTupleTypes = 512 -> Microsoft.CodeAnalysis.SymbolDisplayMiscellaneousOptions -Microsoft.CodeAnalysis.WellKnownGeneratorInputs -Microsoft.CodeAnalysis.WellKnownGeneratorOutputs -override Microsoft.CodeAnalysis.LineMapping.Equals(object? obj) -> bool -override Microsoft.CodeAnalysis.LineMapping.GetHashCode() -> int -override Microsoft.CodeAnalysis.LineMapping.ToString() -> string? -Microsoft.CodeAnalysis.Operations.ISwitchExpressionOperation.IsExhaustive.get -> bool -Microsoft.CodeAnalysis.Operations.OperationWalker -Microsoft.CodeAnalysis.Operations.OperationWalker.OperationWalker() -> void -Microsoft.CodeAnalysis.SourceProductionContext -Microsoft.CodeAnalysis.SourceProductionContext.AddSource(string! hintName, Microsoft.CodeAnalysis.Text.SourceText! sourceText) -> void -Microsoft.CodeAnalysis.SourceProductionContext.AddSource(string! hintName, string! source) -> void -Microsoft.CodeAnalysis.SourceProductionContext.CancellationToken.get -> System.Threading.CancellationToken -Microsoft.CodeAnalysis.SourceProductionContext.ReportDiagnostic(Microsoft.CodeAnalysis.Diagnostic! diagnostic) -> void -Microsoft.CodeAnalysis.SourceProductionContext.SourceProductionContext() -> void -Microsoft.CodeAnalysis.SymbolDisplayPartKind.RecordClassName = 31 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind -const Microsoft.CodeAnalysis.WellKnownDiagnosticTags.CompilationEnd = "CompilationEnd" -> string! -Microsoft.CodeAnalysis.SymbolDisplayPartKind.RecordStructName = 32 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind -Microsoft.CodeAnalysis.SyntaxContextReceiverCreator -Microsoft.CodeAnalysis.SyntaxNode.IsEquivalentTo(Microsoft.CodeAnalysis.SyntaxNode? other) -> bool -Microsoft.CodeAnalysis.SyntaxNode.IsIncrementallyIdenticalTo(Microsoft.CodeAnalysis.SyntaxNode? other) -> bool -Microsoft.CodeAnalysis.SyntaxNodeOrToken.IsIncrementallyIdenticalTo(Microsoft.CodeAnalysis.SyntaxNodeOrToken other) -> bool -Microsoft.CodeAnalysis.SyntaxToken.IsIncrementallyIdenticalTo(Microsoft.CodeAnalysis.SyntaxToken token) -> bool -Microsoft.CodeAnalysis.SyntaxValueProvider -Microsoft.CodeAnalysis.SyntaxValueProvider.CreateSyntaxProvider(System.Func! predicate, System.Func! transform) -> Microsoft.CodeAnalysis.IncrementalValuesProvider -Microsoft.CodeAnalysis.SyntaxValueProvider.SyntaxValueProvider() -> void -override Microsoft.CodeAnalysis.Text.TextChangeRange.ToString() -> string! -readonly Microsoft.CodeAnalysis.GeneratorDriverOptions.DisabledOutputs -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind -readonly Microsoft.CodeAnalysis.GeneratorDriverOptions.TrackIncrementalGeneratorSteps -> bool -static Microsoft.CodeAnalysis.CaseInsensitiveComparison.Compare(System.ReadOnlySpan left, System.ReadOnlySpan right) -> int -static Microsoft.CodeAnalysis.CaseInsensitiveComparison.Equals(System.ReadOnlySpan left, System.ReadOnlySpan right) -> bool -override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGenerators(string! language) -> System.Collections.Immutable.ImmutableArray -override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGeneratorsForAllLanguages() -> System.Collections.Immutable.ImmutableArray -override Microsoft.CodeAnalysis.Operations.OperationWalker.DefaultVisit(Microsoft.CodeAnalysis.IOperation! operation, TArgument argument) -> object? -override Microsoft.CodeAnalysis.Operations.OperationWalker.Visit(Microsoft.CodeAnalysis.IOperation? operation, TArgument argument) -> object? -static Microsoft.CodeAnalysis.Emit.SemanticEdit.operator !=(Microsoft.CodeAnalysis.Emit.SemanticEdit left, Microsoft.CodeAnalysis.Emit.SemanticEdit right) -> bool -static Microsoft.CodeAnalysis.Emit.SemanticEdit.operator ==(Microsoft.CodeAnalysis.Emit.SemanticEdit left, Microsoft.CodeAnalysis.Emit.SemanticEdit right) -> bool -static Microsoft.CodeAnalysis.FileLinePositionSpan.operator !=(Microsoft.CodeAnalysis.FileLinePositionSpan left, Microsoft.CodeAnalysis.FileLinePositionSpan right) -> bool -static Microsoft.CodeAnalysis.FileLinePositionSpan.operator ==(Microsoft.CodeAnalysis.FileLinePositionSpan left, Microsoft.CodeAnalysis.FileLinePositionSpan right) -> bool -static Microsoft.CodeAnalysis.GeneratorExtensions.AsSourceGenerator(this Microsoft.CodeAnalysis.IIncrementalGenerator! incrementalGenerator) -> Microsoft.CodeAnalysis.ISourceGenerator! -static Microsoft.CodeAnalysis.GeneratorExtensions.GetGeneratorType(this Microsoft.CodeAnalysis.ISourceGenerator! generator) -> System.Type! -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.WithTrackingName(this Microsoft.CodeAnalysis.IncrementalValueProvider source, string! name) -> Microsoft.CodeAnalysis.IncrementalValueProvider -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.WithTrackingName(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, string! name) -> Microsoft.CodeAnalysis.IncrementalValuesProvider -static Microsoft.CodeAnalysis.LineMapping.operator !=(Microsoft.CodeAnalysis.LineMapping left, Microsoft.CodeAnalysis.LineMapping right) -> bool -static Microsoft.CodeAnalysis.LineMapping.operator ==(Microsoft.CodeAnalysis.LineMapping left, Microsoft.CodeAnalysis.LineMapping right) -> bool -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Collect(this Microsoft.CodeAnalysis.IncrementalValuesProvider source) -> Microsoft.CodeAnalysis.IncrementalValueProvider> -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Combine(this Microsoft.CodeAnalysis.IncrementalValueProvider provider1, Microsoft.CodeAnalysis.IncrementalValueProvider provider2) -> Microsoft.CodeAnalysis.IncrementalValueProvider<(TLeft Left, TRight Right)> -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Combine(this Microsoft.CodeAnalysis.IncrementalValuesProvider provider1, Microsoft.CodeAnalysis.IncrementalValueProvider provider2) -> Microsoft.CodeAnalysis.IncrementalValuesProvider<(TLeft Left, TRight Right)> -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Select(this Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Func! selector) -> Microsoft.CodeAnalysis.IncrementalValueProvider -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Select(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Func! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.SelectMany(this Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Func!>! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.SelectMany(this Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Func>! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.SelectMany(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Func!>! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.SelectMany(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Func>! selector) -> Microsoft.CodeAnalysis.IncrementalValuesProvider -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.Where(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Func! predicate) -> Microsoft.CodeAnalysis.IncrementalValuesProvider -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.WithComparer(this Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Collections.Generic.IEqualityComparer! comparer) -> Microsoft.CodeAnalysis.IncrementalValueProvider -static Microsoft.CodeAnalysis.IncrementalValueProviderExtensions.WithComparer(this Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Collections.Generic.IEqualityComparer! comparer) -> Microsoft.CodeAnalysis.IncrementalValuesProvider -static Microsoft.CodeAnalysis.Operations.OperationExtensions.GetFunctionPointerSignature(this Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation! functionPointer) -> Microsoft.CodeAnalysis.IMethodSymbol! -virtual Microsoft.CodeAnalysis.Diagnostics.AnalyzerReference.GetGenerators(string! language) -> System.Collections.Immutable.ImmutableArray -virtual Microsoft.CodeAnalysis.Diagnostics.AnalyzerReference.GetGeneratorsForAllLanguages() -> System.Collections.Immutable.ImmutableArray -abstract Microsoft.CodeAnalysis.Compilation.GetUsedAssemblyReferences(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitFunctionPointerInvocation(Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation! operation) -> void -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitImplicitIndexerReference(Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation! operation) -> void -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitFunctionPointerInvocation(Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation! operation, TArgument argument) -> TResult? -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringAddition(Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation! operation) -> void -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringAppend(Microsoft.CodeAnalysis.Operations.IInterpolatedStringAppendOperation! operation) -> void -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringHandlerArgumentPlaceholder(Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation! operation) -> void -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringHandlerCreation(Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation! operation) -> void -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitImplicitIndexerReference(Microsoft.CodeAnalysis.Operations.IImplicitIndexerReferenceOperation! operation, TArgument argument) -> TResult? -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringAddition(Microsoft.CodeAnalysis.Operations.IInterpolatedStringAdditionOperation! operation, TArgument argument) -> TResult? -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringAppend(Microsoft.CodeAnalysis.Operations.IInterpolatedStringAppendOperation! operation, TArgument argument) -> TResult? -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringHandlerArgumentPlaceholder(Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerArgumentPlaceholderOperation! operation, TArgument argument) -> TResult? -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitInterpolatedStringHandlerCreation(Microsoft.CodeAnalysis.Operations.IInterpolatedStringHandlerCreationOperation! operation, TArgument argument) -> TResult? -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitListPattern(Microsoft.CodeAnalysis.Operations.IListPatternOperation! operation) -> void -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSlicePattern(Microsoft.CodeAnalysis.Operations.ISlicePatternOperation! operation) -> void -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitListPattern(Microsoft.CodeAnalysis.Operations.IListPatternOperation! operation, TArgument argument) -> TResult? -virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSlicePattern(Microsoft.CodeAnalysis.Operations.ISlicePatternOperation! operation, TArgument argument) -> TResult? +Microsoft.CodeAnalysis.IOperation.ChildOperations.get -> Microsoft.CodeAnalysis.IOperation.OperationList +Microsoft.CodeAnalysis.IOperation.OperationList +Microsoft.CodeAnalysis.IOperation.OperationList.Any() -> bool +Microsoft.CodeAnalysis.IOperation.OperationList.OperationList() -> void +Microsoft.CodeAnalysis.IOperation.OperationList.Count.get -> int +Microsoft.CodeAnalysis.IOperation.OperationList.First() -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.IOperation.OperationList.GetEnumerator() -> Microsoft.CodeAnalysis.IOperation.OperationList.Enumerator +Microsoft.CodeAnalysis.IOperation.OperationList.Last() -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.IOperation.OperationList.Reverse() -> Microsoft.CodeAnalysis.IOperation.OperationList.Reversed +Microsoft.CodeAnalysis.IOperation.OperationList.ToImmutableArray() -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.IOperation.OperationList.Enumerator +Microsoft.CodeAnalysis.IOperation.OperationList.Enumerator.Current.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.IOperation.OperationList.Enumerator.Enumerator() -> void +Microsoft.CodeAnalysis.IOperation.OperationList.Enumerator.MoveNext() -> bool +Microsoft.CodeAnalysis.IOperation.OperationList.Enumerator.Reset() -> void +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Enumerator +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Enumerator.Current.get -> Microsoft.CodeAnalysis.IOperation! +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Enumerator.Enumerator() -> void +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Enumerator.MoveNext() -> bool +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Enumerator.Reset() -> void +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Reversed() -> void +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Count.get -> int +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.GetEnumerator() -> Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Enumerator +Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.ToImmutableArray() -> System.Collections.Immutable.ImmutableArray +override sealed Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool +*REMOVED*static Microsoft.CodeAnalysis.SyntaxNodeExtensions.ReplaceSyntax(this TRoot! root, System.Collections.Generic.IEnumerable! nodes, System.Func! computeReplacementNode, System.Collections.Generic.IEnumerable! tokens, System.Func! computeReplacementToken, System.Collections.Generic.IEnumerable! trivia, System.Func! computeReplacementTrivia) -> TRoot! +static Microsoft.CodeAnalysis.SyntaxNodeExtensions.ReplaceSyntax(this TRoot! root, System.Collections.Generic.IEnumerable? nodes, System.Func? computeReplacementNode, System.Collections.Generic.IEnumerable? tokens, System.Func? computeReplacementToken, System.Collections.Generic.IEnumerable? trivia, System.Func? computeReplacementTrivia) -> TRoot! diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs index d4d845a7c20eb..f85f65efeb782 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -37,7 +36,7 @@ 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, driverOptions.DisabledOutputs, runtime: TimeSpan.Zero, driverOptions.TrackIncrementalGeneratorSteps); + _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); } public GeneratorDriver RunGenerators(Compilation compilation, CancellationToken cancellationToken = default) @@ -172,7 +171,7 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos var state = _state; var stateBuilder = ArrayBuilder.GetInstance(state.Generators.Length); var constantSourcesBuilder = ArrayBuilder.GetInstance(); - var syntaxInputNodes = ArrayBuilder.GetInstance(); + var syntaxInputNodes = ArrayBuilder.GetInstance(); for (int i = 0; i < state.IncrementalGenerators.Length; i++) { @@ -184,7 +183,7 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos if (!generatorState.Initialized) { var outputBuilder = ArrayBuilder.GetInstance(); - var inputBuilder = ArrayBuilder.GetInstance(); + var inputBuilder = ArrayBuilder.GetInstance(); var postInitSources = ImmutableArray.Empty; var pipelineContext = new IncrementalGeneratorInitializationContext(inputBuilder, outputBuilder, SourceExtension); @@ -193,9 +192,7 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos { generator.Initialize(pipelineContext); } -#pragma warning disable CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete; tracked by https://github.com/dotnet/roslyn/issues/58375 - catch (Exception e) when (FatalError.ReportIfNonFatalAndCatchUnlessCanceled(e, cancellationToken)) -#pragma warning restore CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete + catch (Exception e) { ex = e; } @@ -244,7 +241,9 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos } constantSourcesBuilder.Free(); - var driverStateBuilder = new DriverStateTable.Builder(compilation, _state, syntaxInputNodes.ToImmutableAndFree(), cancellationToken); + var syntaxStoreBuilder = _state.SyntaxStore.ToBuilder(compilation, syntaxInputNodes.ToImmutableAndFree(), _state.TrackIncrementalSteps, cancellationToken); + + var driverStateBuilder = new DriverStateTable.Builder(compilation, _state, syntaxStoreBuilder, cancellationToken); for (int i = 0; i < state.IncrementalGenerators.Length; i++) { var generatorState = stateBuilder[i]; @@ -269,7 +268,7 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos } } - state = state.With(stateTable: driverStateBuilder.ToImmutable(), generatorStates: stateBuilder.ToImmutableAndFree(), runTime: timer.Elapsed); + state = state.With(stateTable: driverStateBuilder.ToImmutable(), syntaxStore: syntaxStoreBuilder.ToImmutable(), generatorStates: stateBuilder.ToImmutableAndFree(), runTime: timer.Elapsed); return state; } diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriverState.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriverState.cs index 9722e05629adb..dc77d95c9d0b0 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriverState.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriverState.cs @@ -18,6 +18,7 @@ internal GeneratorDriverState(ParseOptions parseOptions, ImmutableArray additionalTexts, ImmutableArray generatorStates, DriverStateTable stateTable, + SyntaxStore syntaxStore, IncrementalGeneratorOutputKind disabledOutputs, TimeSpan runtime, bool trackIncrementalGeneratorSteps) @@ -29,6 +30,7 @@ internal GeneratorDriverState(ParseOptions parseOptions, ParseOptions = parseOptions; OptionsProvider = optionsProvider; StateTable = stateTable; + SyntaxStore = syntaxStore; DisabledOutputs = disabledOutputs; RunTime = runtime; TrackIncrementalSteps = trackIncrementalGeneratorSteps; @@ -80,6 +82,8 @@ internal GeneratorDriverState(ParseOptions parseOptions, internal readonly DriverStateTable StateTable; + internal readonly SyntaxStore SyntaxStore; + /// /// A bit field containing the output kinds that should not be produced by this generator driver. /// @@ -95,6 +99,7 @@ internal GeneratorDriverState With( ImmutableArray? generatorStates = null, ImmutableArray? additionalTexts = null, DriverStateTable? stateTable = null, + SyntaxStore? syntaxStore = null, ParseOptions? parseOptions = null, AnalyzerConfigOptionsProvider? optionsProvider = null, IncrementalGeneratorOutputKind? disabledOutputs = null, @@ -108,6 +113,7 @@ internal GeneratorDriverState With( additionalTexts ?? this.AdditionalTexts, generatorStates ?? this.GeneratorStates, stateTable ?? this.StateTable, + syntaxStore ?? this.SyntaxStore, disabledOutputs ?? this.DisabledOutputs, runTime ?? this.RunTime, this.TrackIncrementalSteps diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs index 399425610dca2..64a3a86b6e46c 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs @@ -24,14 +24,14 @@ public GeneratorState(GeneratorInfo info) /// Creates a new generator state that contains information and constant trees /// public GeneratorState(GeneratorInfo info, ImmutableArray postInitTrees) - : this(info, postInitTrees, ImmutableArray.Empty, ImmutableArray.Empty) + : this(info, postInitTrees, ImmutableArray.Empty, ImmutableArray.Empty) { } /// /// Creates a new generator state that contains information, constant trees and an execution pipeline /// - public GeneratorState(GeneratorInfo info, ImmutableArray postInitTrees, ImmutableArray inputNodes, ImmutableArray outputNodes) + public GeneratorState(GeneratorInfo info, ImmutableArray postInitTrees, ImmutableArray inputNodes, ImmutableArray outputNodes) : this(info, postInitTrees, inputNodes, outputNodes, ImmutableArray.Empty, ImmutableArray.Empty, ImmutableDictionary>.Empty, ImmutableDictionary>.Empty, exception: null, elapsedTime: TimeSpan.Zero) { } @@ -40,19 +40,19 @@ public GeneratorState(GeneratorInfo info, ImmutableArray po /// Creates a new generator state that contains an exception and the associated diagnostic /// public GeneratorState(GeneratorInfo info, Exception e, Diagnostic error, TimeSpan elapsedTime) - : this(info, ImmutableArray.Empty, ImmutableArray.Empty, ImmutableArray.Empty, ImmutableArray.Empty, ImmutableArray.Create(error), ImmutableDictionary>.Empty, ImmutableDictionary>.Empty, exception: e, elapsedTime: elapsedTime) + : this(info, ImmutableArray.Empty, ImmutableArray.Empty, ImmutableArray.Empty, ImmutableArray.Empty, ImmutableArray.Create(error), ImmutableDictionary>.Empty, ImmutableDictionary>.Empty, exception: e, elapsedTime: elapsedTime) { } /// /// Creates a generator state that contains results /// - public GeneratorState(GeneratorInfo info, ImmutableArray postInitTrees, ImmutableArray inputNodes, ImmutableArray outputNodes, ImmutableArray generatedTrees, ImmutableArray diagnostics, ImmutableDictionary> executedSteps, ImmutableDictionary> outputSteps, TimeSpan elapsedTime) + public GeneratorState(GeneratorInfo info, ImmutableArray postInitTrees, ImmutableArray inputNodes, ImmutableArray outputNodes, ImmutableArray generatedTrees, ImmutableArray diagnostics, ImmutableDictionary> executedSteps, ImmutableDictionary> outputSteps, TimeSpan elapsedTime) : this(info, postInitTrees, inputNodes, outputNodes, generatedTrees, diagnostics, executedSteps, outputSteps, exception: null, elapsedTime) { } - private GeneratorState(GeneratorInfo info, ImmutableArray postInitTrees, ImmutableArray inputNodes, ImmutableArray outputNodes, ImmutableArray generatedTrees, ImmutableArray diagnostics, ImmutableDictionary> executedSteps, ImmutableDictionary> outputSteps, Exception? exception, TimeSpan elapsedTime) + private GeneratorState(GeneratorInfo info, ImmutableArray postInitTrees, ImmutableArray inputNodes, ImmutableArray outputNodes, ImmutableArray generatedTrees, ImmutableArray diagnostics, ImmutableDictionary> executedSteps, ImmutableDictionary> outputSteps, Exception? exception, TimeSpan elapsedTime) { this.Initialized = true; this.PostInitTrees = postInitTrees; @@ -71,7 +71,7 @@ private GeneratorState(GeneratorInfo info, ImmutableArray p internal ImmutableArray PostInitTrees { get; } - internal ImmutableArray InputNodes { get; } + internal ImmutableArray InputNodes { get; } internal ImmutableArray OutputNodes { get; } diff --git a/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs b/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs index db4a3acb0b814..275f62214ab3e 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs @@ -17,11 +17,11 @@ namespace Microsoft.CodeAnalysis /// public readonly struct IncrementalGeneratorInitializationContext { - private readonly ArrayBuilder _syntaxInputBuilder; + private readonly ArrayBuilder _syntaxInputBuilder; private readonly ArrayBuilder _outputNodes; private readonly string _sourceExtension; - internal IncrementalGeneratorInitializationContext(ArrayBuilder syntaxInputBuilder, ArrayBuilder outputNodes, string sourceExtension) + internal IncrementalGeneratorInitializationContext(ArrayBuilder syntaxInputBuilder, ArrayBuilder outputNodes, string sourceExtension) { _syntaxInputBuilder = syntaxInputBuilder; _outputNodes = outputNodes; @@ -38,7 +38,7 @@ internal IncrementalGeneratorInitializationContext(ArrayBuilder AnalyzerConfigOptionsProvider => new IncrementalValueProvider(SharedInputNodes.AnalyzerConfigOptions.WithRegisterOutput(RegisterOutput).WithTrackingName(WellKnownGeneratorInputs.AnalyzerConfigOptions)); - public IncrementalValueProvider MetadataReferencesProvider => new IncrementalValueProvider(SharedInputNodes.MetadataReferences.WithRegisterOutput(RegisterOutput).WithTrackingName(WellKnownGeneratorInputs.MetadataReferences)); + public IncrementalValuesProvider MetadataReferencesProvider => new IncrementalValuesProvider(SharedInputNodes.MetadataReferences.WithRegisterOutput(RegisterOutput).WithTrackingName(WellKnownGeneratorInputs.MetadataReferences)); public void RegisterSourceOutput(IncrementalValueProvider source, Action action) => RegisterSourceOutput(source.Node, action, IncrementalGeneratorOutputKind.Source, _sourceExtension); diff --git a/src/Compilers/Core/Portable/SourceGeneration/IncrementalGeneratorSyntaxWalker.cs b/src/Compilers/Core/Portable/SourceGeneration/IncrementalGeneratorSyntaxWalker.cs deleted file mode 100644 index b4df0848178ae..0000000000000 --- a/src/Compilers/Core/Portable/SourceGeneration/IncrementalGeneratorSyntaxWalker.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Text; -using System.Threading; -using Microsoft.CodeAnalysis.PooledObjects; - -namespace Microsoft.CodeAnalysis -{ - internal sealed class IncrementalGeneratorSyntaxWalker : SyntaxWalker - { - private readonly Func _filter; - private readonly CancellationToken _token; - private ArrayBuilder? _results; - - internal IncrementalGeneratorSyntaxWalker(Func filter, CancellationToken token) - { - _filter = filter; - _token = token; - } - - public static ImmutableArray GetFilteredNodes(SyntaxNode root, Func func, CancellationToken token) - { - var walker = new IncrementalGeneratorSyntaxWalker(func, token); - walker.Visit(root); - return walker._results.ToImmutableOrEmptyAndFree(); - } - - public override void Visit(SyntaxNode node) - { - _token.ThrowIfCancellationRequested(); - - if (_filter(node, _token)) - { - (_results ??= ArrayBuilder.GetInstance()).Add(node); - } - base.Visit(node); - } - } -} diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/DriverStateTable.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/DriverStateTable.cs index c6ca15c5ca9fd..edf3b8a681ef8 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/DriverStateTable.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/DriverStateTable.cs @@ -14,29 +14,18 @@ namespace Microsoft.CodeAnalysis { internal sealed class DriverStateTable { - private readonly ImmutableSegmentedDictionary _tables; + private readonly StateTableStore _tables; - internal static DriverStateTable Empty { get; } = new DriverStateTable(ImmutableSegmentedDictionary.Empty); + internal static DriverStateTable Empty { get; } = new DriverStateTable(StateTableStore.Empty); - private DriverStateTable(ImmutableSegmentedDictionary tables) + private DriverStateTable(StateTableStore tables) { _tables = tables; } - public NodeStateTable GetStateTableOrEmpty(object input) - { - if (_tables.TryGetValue(input, out var result)) - { - return (NodeStateTable)result; - } - return NodeStateTable.Empty; - } - public sealed class Builder { - private readonly ImmutableSegmentedDictionary.Builder _tableBuilder = ImmutableSegmentedDictionary.CreateBuilder(); - private readonly ImmutableArray _syntaxInputNodes; - private readonly ImmutableDictionary.Builder _syntaxExceptions = ImmutableDictionary.CreateBuilder(); + private readonly StateTableStore.Builder _stateTableBuilder = new StateTableStore.Builder(); private readonly DriverStateTable _previousTable; private readonly CancellationToken _cancellationToken; @@ -44,110 +33,31 @@ public sealed class Builder public Compilation Compilation { get; } - public Builder(Compilation compilation, GeneratorDriverState driverState, ImmutableArray syntaxInputNodes, CancellationToken cancellationToken = default) + internal SyntaxStore.Builder SyntaxStore { get; } + + public Builder(Compilation compilation, GeneratorDriverState driverState, SyntaxStore.Builder syntaxStore, CancellationToken cancellationToken = default) { Compilation = compilation; DriverState = driverState; _previousTable = driverState.StateTable; - _syntaxInputNodes = syntaxInputNodes; _cancellationToken = cancellationToken; - } - - public IStateTable GetSyntaxInputTable(ISyntaxInputNode syntaxInputNode) - { - Debug.Assert(_syntaxInputNodes.Contains(syntaxInputNode)); - - // when we don't have a value for this node, we update all the syntax inputs at once - if (!_tableBuilder.ContainsKey(syntaxInputNode)) - { - // CONSIDER: when the compilation is the same as previous, the syntax trees must also be the same. - // if we have a previous state table for a node, we can just short circuit knowing that it is up to date - // This step isn't part of the tree, so we can skip recording. - var compilationIsCached = GetLatestStateTableForNode(SharedInputNodes.Compilation).IsCached; - - // get a builder for each input node - var syntaxInputBuilders = ArrayBuilder.GetInstance(_syntaxInputNodes.Length); - foreach (var node in _syntaxInputNodes) - { - // TODO: We don't cache the tracked incremental steps in a manner that we can easily rehydrate between runs, - // so we'll disable the cached compilation perf optimization when incremental step tracking is enabled. - if (compilationIsCached && !DriverState.TrackIncrementalSteps && _previousTable._tables.TryGetValue(node, out var previousStateTable)) - { - _tableBuilder.Add(node, previousStateTable); - } - else - { - syntaxInputBuilders.Add(node.GetBuilder(_previousTable, DriverState.TrackIncrementalSteps)); - } - } - - if (syntaxInputBuilders.Count == 0) - { - // bring over the previously cached syntax tree inputs - _tableBuilder[SharedInputNodes.SyntaxTrees] = _previousTable._tables[SharedInputNodes.SyntaxTrees]; - } - else - { - GeneratorRunStateTable.Builder temporaryRunStateBuilder = new GeneratorRunStateTable.Builder(DriverState.TrackIncrementalSteps); - NodeStateTable syntaxTreeState = GetLatestStateTableForNode(SharedInputNodes.SyntaxTrees); - - // update each tree for the builders, sharing the semantic model - foreach ((var tree, var state, var syntaxTreeIndex, var stepInfo) in syntaxTreeState) - { - var root = new Lazy(() => tree.GetRoot(_cancellationToken)); - var model = state != EntryState.Removed ? Compilation.GetSemanticModel(tree) : null; - for (int i = 0; i < syntaxInputBuilders.Count; i++) - { - try - { - _cancellationToken.ThrowIfCancellationRequested(); - syntaxInputBuilders[i].VisitTree(root, state, model, _cancellationToken); - } - catch (UserFunctionException ufe) - { - // we're evaluating this node ahead of time, so we can't just throw the exception - // instead we'll hold onto it, and throw the exception when a downstream node actually - // attempts to read the value - _syntaxExceptions[syntaxInputBuilders[i].SyntaxInputNode] = ufe; - syntaxInputBuilders.RemoveAt(i); - i--; - } - } - } - - // save the updated inputs - foreach (ISyntaxInputBuilder builder in syntaxInputBuilders) - { - builder.SaveStateAndFree(_tableBuilder); - Debug.Assert(_tableBuilder.ContainsKey(builder.SyntaxInputNode)); - } - } - syntaxInputBuilders.Free(); - } - - // if we don't have an entry for this node, it must have thrown an exception - if (!_tableBuilder.ContainsKey(syntaxInputNode)) - { - throw _syntaxExceptions[syntaxInputNode]; - } - - return _tableBuilder[syntaxInputNode]; + SyntaxStore = syntaxStore; } public NodeStateTable GetLatestStateTableForNode(IIncrementalGeneratorNode source) { // if we've already evaluated a node during this build, we can just return the existing result - if (_tableBuilder.ContainsKey(source)) + if (_stateTableBuilder.TryGetTable(source, out var table)) { - return (NodeStateTable)_tableBuilder[source]; + return (NodeStateTable)table; } // get the previous table, if there was one for this node - NodeStateTable previousTable = _previousTable.GetStateTableOrEmpty(source); + NodeStateTable previousTable = _previousTable._tables.GetStateTableOrEmpty(source); // request the node update its state based on the current driver table and store the new result var newTable = source.UpdateStateTable(this, previousTable, _cancellationToken); - _tableBuilder[source] = newTable; + _stateTableBuilder.SetTable(source, newTable); return newTable; } @@ -158,14 +68,7 @@ public NodeStateTable.Builder CreateTableBuilder(NodeStateTable previou public DriverStateTable ToImmutable() { - // we can compact the tables at this point, as we'll no longer be using them to determine current state - var keys = _tableBuilder.Keys.ToArray(); - foreach (var key in keys) - { - _tableBuilder[key] = _tableBuilder[key].AsCached(); - } - - return new DriverStateTable(_tableBuilder.ToImmutable()); + return new DriverStateTable(_stateTableBuilder.ToImmutable()); } } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/ISyntaxInputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/ISyntaxStrategy.cs similarity index 62% rename from src/Compilers/Core/Portable/SourceGeneration/Nodes/ISyntaxInputNode.cs rename to src/Compilers/Core/Portable/SourceGeneration/Nodes/ISyntaxStrategy.cs index 9bcb86404fb96..4d2a607c5d052 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/ISyntaxInputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/ISyntaxStrategy.cs @@ -3,22 +3,21 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Threading; using Microsoft.CodeAnalysis.Collections; namespace Microsoft.CodeAnalysis { - internal interface ISyntaxInputNode + internal interface ISyntaxSelectionStrategy { - ISyntaxInputBuilder GetBuilder(DriverStateTable table, bool trackIncrementalSteps); + ISyntaxInputBuilder GetBuilder(StateTableStore tableStore, object key, bool trackIncrementalSteps, string? name, IEqualityComparer comparer); } internal interface ISyntaxInputBuilder { - ISyntaxInputNode SyntaxInputNode { get; } - void VisitTree(Lazy root, EntryState state, SemanticModel? model, CancellationToken cancellationToken); - void SaveStateAndFree(ImmutableSegmentedDictionary.Builder tables); + void SaveStateAndFree(StateTableStore.Builder tableStoreBuilder); } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/PostInitOutputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/PostInitOutputNode.cs index cd55a2de97631..550b79682bb0f 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/PostInitOutputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/PostInitOutputNode.cs @@ -9,9 +9,9 @@ namespace Microsoft.CodeAnalysis { internal sealed class PostInitOutputNode : IIncrementalGeneratorOutputNode { - private readonly Action _callback; + private readonly Action _callback; - public PostInitOutputNode(Action callback) + public PostInitOutputNode(Action callback) { _callback = callback; } @@ -20,7 +20,7 @@ public PostInitOutputNode(Action public void AppendOutputs(IncrementalExecutionContext context, CancellationToken cancellationToken) { - _callback(new IncrementalGeneratorPostInitializationContext(context.Sources, cancellationToken)); + _callback(new IncrementalGeneratorPostInitializationContext(context.Sources, cancellationToken), cancellationToken); } } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/PredicateSyntaxStrategy.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/PredicateSyntaxStrategy.cs new file mode 100644 index 0000000000000..29b759e70446a --- /dev/null +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/PredicateSyntaxStrategy.cs @@ -0,0 +1,118 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Threading; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis +{ + internal sealed class PredicateSyntaxStrategy : ISyntaxSelectionStrategy + { + private readonly Func _transformFunc; + private readonly Func _filterFunc; + private readonly object _filterKey = new object(); + + internal PredicateSyntaxStrategy(Func filterFunc, Func transformFunc) + { + _transformFunc = transformFunc; + _filterFunc = filterFunc; + } + + public ISyntaxInputBuilder GetBuilder(StateTableStore table, object key, bool trackIncrementalSteps, string? name, IEqualityComparer? comparer) => new Builder(this, key, table, trackIncrementalSteps, name, comparer ?? EqualityComparer.Default); + + private sealed class Builder : ISyntaxInputBuilder + { + private readonly PredicateSyntaxStrategy _owner; + private readonly string? _name; + private readonly IEqualityComparer _comparer; + private readonly object _key; + private readonly NodeStateTable.Builder _filterTable; + + private readonly NodeStateTable.Builder _transformTable; + + public Builder(PredicateSyntaxStrategy owner, object key, StateTableStore table, bool trackIncrementalSteps, string? name, IEqualityComparer comparer) + { + _owner = owner; + _name = name; + _comparer = comparer; + _key = key; + _filterTable = table.GetStateTableOrEmpty(_owner._filterKey).ToBuilder(stepName: null, trackIncrementalSteps); + _transformTable = table.GetStateTableOrEmpty(_key).ToBuilder(_name, trackIncrementalSteps); + } + + public void SaveStateAndFree(StateTableStore.Builder tables) + { + tables.SetTable(_owner._filterKey, _filterTable.ToImmutableAndFree()); + tables.SetTable(_key, _transformTable.ToImmutableAndFree()); + } + + public void VisitTree(Lazy root, EntryState state, SemanticModel? model, CancellationToken cancellationToken) + { + // We always have no inputs steps into a SyntaxInputNode, but we track the difference between "no inputs" (empty collection) and "no step information" (default value) + var noInputStepsStepInfo = _filterTable.TrackIncrementalSteps ? ImmutableArray<(IncrementalGeneratorRunStep, int)>.Empty : default; + if (state == EntryState.Removed) + { + // mark both syntax *and* transform nodes removed + if (_filterTable.TryRemoveEntries(TimeSpan.Zero, noInputStepsStepInfo, out ImmutableArray removedNodes)) + { + for (int i = 0; i < removedNodes.Length; i++) + { + _transformTable.TryRemoveEntries(TimeSpan.Zero, noInputStepsStepInfo); + } + } + } + else + { + Debug.Assert(model is object); + + // get the syntax nodes from cache, or a syntax walk using the filter + if (state != EntryState.Cached || !_filterTable.TryUseCachedEntries(TimeSpan.Zero, noInputStepsStepInfo, out ImmutableArray nodes)) + { + var stopwatch = SharedStopwatch.StartNew(); + nodes = getFilteredNodes(root.Value, _owner._filterFunc, cancellationToken); + _filterTable.AddEntries(nodes, state, stopwatch.Elapsed, noInputStepsStepInfo, state); + } + + // now, using the obtained syntax nodes, run the transform + foreach (SyntaxNode node in nodes) + { + var stopwatch = SharedStopwatch.StartNew(); + var value = new GeneratorSyntaxContext(node, model); + var transformed = _owner._transformFunc(value, cancellationToken); + + // The SemanticModel we provide to GeneratorSyntaxContext is never guaranteed to be the same between runs, + // so we never consider the input to the transform as cached. + var transformInputState = state == EntryState.Cached ? EntryState.Modified : state; + + if (transformInputState == EntryState.Added || !_transformTable.TryModifyEntry(transformed, _comparer, stopwatch.Elapsed, noInputStepsStepInfo, transformInputState)) + { + _transformTable.AddEntry(transformed, EntryState.Added, stopwatch.Elapsed, noInputStepsStepInfo, EntryState.Added); + } + } + } + + static ImmutableArray getFilteredNodes(SyntaxNode root, Func func, CancellationToken token) + { + ArrayBuilder? results = null; + foreach (var node in root.DescendantNodesAndSelf()) + { + token.ThrowIfCancellationRequested(); + + if (func(node, token)) + { + (results ??= ArrayBuilder.GetInstance()).Add(node); + } + } + + return results.ToImmutableOrEmptyAndFree(); + } + } + } + } +} diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SourceOutputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SourceOutputNode.cs index 3e8dc48ef4d4b..b6b715f807af5 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SourceOutputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SourceOutputNode.cs @@ -17,13 +17,13 @@ internal sealed class SourceOutputNode : IIncrementalGeneratorOutputNode { private readonly IIncrementalGeneratorNode _source; - private readonly Action _action; + private readonly Action _action; private readonly IncrementalGeneratorOutputKind _outputKind; private readonly string _sourceExtension; - public SourceOutputNode(IIncrementalGeneratorNode source, Action action, IncrementalGeneratorOutputKind outputKind, string sourceExtension) + public SourceOutputNode(IIncrementalGeneratorNode source, Action action, IncrementalGeneratorOutputKind outputKind, string sourceExtension) { _source = source; _action = action; @@ -70,7 +70,7 @@ public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphSt try { var stopwatch = SharedStopwatch.StartNew(); - _action(context, entry.Item); + _action(context, entry.Item, cancellationToken); var sourcesAndDiagnostics = (sourcesBuilder.ToImmutable(), diagnostics.ToReadOnly()); nodeTable.AddEntry(sourcesAndDiagnostics, EntryState.Added, stopwatch.Elapsed, inputs, EntryState.Added); } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/StateTableStore.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/StateTableStore.cs new file mode 100644 index 0000000000000..3605b7fdefa32 --- /dev/null +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/StateTableStore.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis.Collections; + +namespace Microsoft.CodeAnalysis +{ + internal sealed class StateTableStore + { + private readonly ImmutableSegmentedDictionary _tables; + + public static readonly StateTableStore Empty = new StateTableStore(ImmutableSegmentedDictionary.Empty); + + private StateTableStore(ImmutableSegmentedDictionary tables) + { + _tables = tables; + } + + public bool TryGetValue(object key, [NotNullWhen(true)] out IStateTable? table) => _tables.TryGetValue(key, out table); + + public NodeStateTable GetStateTableOrEmpty(object input) + { + if (TryGetValue(input, out var output)) + { + return (NodeStateTable)output; + } + return NodeStateTable.Empty; + } + + public sealed class Builder + { + private readonly ImmutableSegmentedDictionary.Builder _tableBuilder = ImmutableSegmentedDictionary.CreateBuilder(); + + public bool Contains(object key) => _tableBuilder.ContainsKey(key); + + public bool TryGetTable(object key, [NotNullWhen(true)] out IStateTable? table) => _tableBuilder.TryGetValue(key, out table); + + public void SetTable(object key, IStateTable table) => _tableBuilder[key] = table; + + public StateTableStore ToImmutable() + { + // we can cache the tables at this point, as we'll no longer be using them to determine current state + var keys = _tableBuilder.Keys.ToArray(); + foreach (var key in keys) + { + _tableBuilder[key] = _tableBuilder[key].AsCached(); + } + + return new StateTableStore(_tableBuilder.ToImmutable()); + } + } + } +} diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxInputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxInputNode.cs index fbe9860abfe0c..c3bf9fad96b4e 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxInputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxInputNode.cs @@ -4,110 +4,41 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics; using System.Threading; -using Microsoft.CodeAnalysis.Collections; -using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { - internal sealed class SyntaxInputNode : IIncrementalGeneratorNode, ISyntaxInputNode + internal abstract class SyntaxInputNode { - private readonly Func _transformFunc; - private readonly Action _registerOutputAndNode; - private readonly Func _filterFunc; + internal abstract ISyntaxInputBuilder GetBuilder(StateTableStore table, bool trackIncrementalSteps); + } + + internal sealed class SyntaxInputNode : SyntaxInputNode, IIncrementalGeneratorNode + { + private readonly ISyntaxSelectionStrategy _inputNode; + private readonly Action _registerOutput; private readonly IEqualityComparer _comparer; - private readonly object _filterKey = new object(); + private readonly string? _name; - internal SyntaxInputNode(Func filterFunc, Func transformFunc, Action registerOutputAndNode, IEqualityComparer? comparer = null, string? name = null) + internal SyntaxInputNode(ISyntaxSelectionStrategy inputNode, Action registerOutput, IEqualityComparer? comparer = null, string? name = null) { - _transformFunc = transformFunc; - _registerOutputAndNode = registerOutputAndNode; - _filterFunc = filterFunc; + _inputNode = inputNode; + _registerOutput = registerOutput; _comparer = comparer ?? EqualityComparer.Default; - Name = name; + _name = name; } public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphState, NodeStateTable previousTable, CancellationToken cancellationToken) { - return (NodeStateTable)graphState.GetSyntaxInputTable(this); + return (NodeStateTable)graphState.SyntaxStore.GetSyntaxInputTable(this, graphState.GetLatestStateTableForNode(SharedInputNodes.SyntaxTrees)); } - public IIncrementalGeneratorNode WithComparer(IEqualityComparer comparer) => new SyntaxInputNode(_filterFunc, _transformFunc, _registerOutputAndNode, comparer, Name); - - public IIncrementalGeneratorNode WithTrackingName(string name) => new SyntaxInputNode(_filterFunc, _transformFunc, _registerOutputAndNode, _comparer, name); + public IIncrementalGeneratorNode WithComparer(IEqualityComparer comparer) => new SyntaxInputNode(_inputNode, _registerOutput, comparer, _name); - public ISyntaxInputBuilder GetBuilder(DriverStateTable table, bool trackIncrementalSteps) => new Builder(this, table, trackIncrementalSteps); - - public void RegisterOutput(IIncrementalGeneratorOutputNode output) => _registerOutputAndNode(this, output); - - private string? Name { get; } - - private sealed class Builder : ISyntaxInputBuilder - { - private readonly SyntaxInputNode _owner; - private readonly NodeStateTable.Builder _filterTable; + public IIncrementalGeneratorNode WithTrackingName(string name) => new SyntaxInputNode(_inputNode, _registerOutput, _comparer, name); - private readonly NodeStateTable.Builder _transformTable; + public void RegisterOutput(IIncrementalGeneratorOutputNode output) => _registerOutput(this, output); - public Builder(SyntaxInputNode owner, DriverStateTable table, bool trackIncrementalSteps) - { - _owner = owner; - _filterTable = table.GetStateTableOrEmpty(_owner._filterKey).ToBuilder(stepName: null, trackIncrementalSteps); - _transformTable = table.GetStateTableOrEmpty(_owner).ToBuilder(_owner.Name, trackIncrementalSteps); - } - - public ISyntaxInputNode SyntaxInputNode { get => _owner; } - - public void SaveStateAndFree(ImmutableSegmentedDictionary.Builder tables) - { - tables[_owner._filterKey] = _filterTable.ToImmutableAndFree(); - tables[_owner] = _transformTable.ToImmutableAndFree(); - } - - public void VisitTree(Lazy root, EntryState state, SemanticModel? model, CancellationToken cancellationToken) - { - // We always have no inputs steps into a SyntaxInputNode, but we track the difference between "no inputs" (empty collection) and "no step information" (default value) - var noInputStepsStepInfo = _filterTable.TrackIncrementalSteps ? ImmutableArray<(IncrementalGeneratorRunStep, int)>.Empty : default; - if (state == EntryState.Removed) - { - // mark both syntax *and* transform nodes removed - if (_filterTable.TryRemoveEntries(TimeSpan.Zero, noInputStepsStepInfo, out ImmutableArray removedNodes)) - { - for (int i = 0; i < removedNodes.Length; i++) - { - _transformTable.TryRemoveEntries(TimeSpan.Zero, noInputStepsStepInfo); - } - } - } - else - { - Debug.Assert(model is object); - - // get the syntax nodes from cache, or a syntax walk using the filter - if (state != EntryState.Cached || !_filterTable.TryUseCachedEntries(TimeSpan.Zero, noInputStepsStepInfo, out ImmutableArray nodes)) - { - var stopwatch = SharedStopwatch.StartNew(); - nodes = IncrementalGeneratorSyntaxWalker.GetFilteredNodes(root.Value, _owner._filterFunc, cancellationToken); - _filterTable.AddEntries(nodes, state, stopwatch.Elapsed, noInputStepsStepInfo, state); - } - - // now, using the obtained syntax nodes, run the transform - foreach (SyntaxNode node in nodes) - { - var stopwatch = SharedStopwatch.StartNew(); - var value = new GeneratorSyntaxContext(node, model); - var transformed = _owner._transformFunc(value, cancellationToken); - - if (state == EntryState.Added || !_transformTable.TryModifyEntry(transformed, _owner._comparer, stopwatch.Elapsed, noInputStepsStepInfo, state)) - { - _transformTable.AddEntry(transformed, EntryState.Added, stopwatch.Elapsed, noInputStepsStepInfo, EntryState.Added); - } - } - } - } - } + internal override ISyntaxInputBuilder GetBuilder(StateTableStore table, bool trackIncrementalSteps) => _inputNode.GetBuilder(table, this, trackIncrementalSteps, _name, _comparer); } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxReceiverInputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxReceiverStrategy.cs similarity index 57% rename from src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxReceiverInputNode.cs rename to src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxReceiverStrategy.cs index 865edba0763b1..3f5c34df0ae81 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxReceiverInputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxReceiverStrategy.cs @@ -5,58 +5,38 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Threading; -using Microsoft.CodeAnalysis.Collections; -using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { - internal sealed class SyntaxReceiverInputNode : ISyntaxInputNode, IIncrementalGeneratorNode + internal sealed class SyntaxReceiverStrategy : ISyntaxSelectionStrategy { private readonly SyntaxContextReceiverCreator _receiverCreator; private readonly Action _registerOutput; - public SyntaxReceiverInputNode(SyntaxContextReceiverCreator receiverCreator, Action registerOutput) + public SyntaxReceiverStrategy(SyntaxContextReceiverCreator receiverCreator, Action registerOutput) { _receiverCreator = receiverCreator; _registerOutput = registerOutput; } - public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphState, NodeStateTable previousTable, CancellationToken cancellationToken) - { - return (NodeStateTable)graphState.GetSyntaxInputTable(this); - } - - public IIncrementalGeneratorNode WithComparer(IEqualityComparer comparer) - { - // we don't expose this node to end users - throw ExceptionUtilities.Unreachable; - } - - public IIncrementalGeneratorNode WithTrackingName(string name) - { - // we don't expose this node to end users - throw ExceptionUtilities.Unreachable; - } - - public ISyntaxInputBuilder GetBuilder(DriverStateTable table, bool trackIncrementalSteps) => new Builder(this, table, trackIncrementalSteps); - - public void RegisterOutput(IIncrementalGeneratorOutputNode output) => _registerOutput(output); + public ISyntaxInputBuilder GetBuilder(StateTableStore table, object key, bool trackIncrementalSteps, string? name, IEqualityComparer? comparer) => new Builder(this, key, table, trackIncrementalSteps); private sealed class Builder : ISyntaxInputBuilder { - private readonly SyntaxReceiverInputNode _owner; + private readonly SyntaxReceiverStrategy _owner; + private readonly object _key; private readonly NodeStateTable.Builder _nodeStateTable; private readonly ISyntaxContextReceiver? _receiver; private readonly GeneratorSyntaxWalker? _walker; private TimeSpan lastElapsedTime; - public Builder(SyntaxReceiverInputNode owner, DriverStateTable driverStateTable, bool trackIncrementalSteps) + public Builder(SyntaxReceiverStrategy owner, object key, StateTableStore driverStateTable, bool trackIncrementalSteps) { _owner = owner; - _nodeStateTable = driverStateTable.GetStateTableOrEmpty(_owner).ToBuilder(stepName: null, trackIncrementalSteps); + _key = key; + _nodeStateTable = driverStateTable.GetStateTableOrEmpty(_key).ToBuilder(stepName: null, trackIncrementalSteps); try { _receiver = owner._receiverCreator(); @@ -72,14 +52,12 @@ public Builder(SyntaxReceiverInputNode owner, DriverStateTable driverStateTable, } } - public ISyntaxInputNode SyntaxInputNode { get => _owner; } - private bool TrackIncrementalSteps => _nodeStateTable.TrackIncrementalSteps; - public void SaveStateAndFree(ImmutableSegmentedDictionary.Builder tables) + public void SaveStateAndFree(StateTableStore.Builder tables) { _nodeStateTable.AddEntry(_receiver, EntryState.Modified, lastElapsedTime, TrackIncrementalSteps ? System.Collections.Immutable.ImmutableArray<(IncrementalGeneratorRunStep, int)>.Empty : default, EntryState.Modified); - tables[_owner] = _nodeStateTable.ToImmutableAndFree(); + tables.SetTable(_key, _nodeStateTable.ToImmutableAndFree()); } public void VisitTree(Lazy root, EntryState state, SemanticModel? model, CancellationToken cancellationToken) @@ -96,7 +74,7 @@ public void VisitTree(Lazy root, EntryState state, SemanticModel? mo lastElapsedTime = stopwatch.Elapsed; } } - catch (Exception e) + catch (Exception e) when (!ExceptionUtilities.IsCurrentOperationBeingCancelled(e, cancellationToken)) { throw new UserFunctionException(e); } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider.cs index f545caef16e4f..69703c2a79256 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider.cs @@ -14,10 +14,10 @@ namespace Microsoft.CodeAnalysis /// public readonly struct SyntaxValueProvider { - private readonly ArrayBuilder _inputNodes; + private readonly ArrayBuilder _inputNodes; private readonly Action _registerOutput; - internal SyntaxValueProvider(ArrayBuilder inputNodes, Action registerOutput) + internal SyntaxValueProvider(ArrayBuilder inputNodes, Action registerOutput) { _inputNodes = inputNodes; _registerOutput = registerOutput; @@ -33,7 +33,7 @@ internal SyntaxValueProvider(ArrayBuilder inputNodes, Action CreateSyntaxProvider(Func predicate, Func transform) { // registration of the input is deferred until we know the node is used - return new IncrementalValuesProvider(new SyntaxInputNode(predicate.WrapUserFunction(), transform.WrapUserFunction(), RegisterOutputAndDeferredInput)); + return new IncrementalValuesProvider(new SyntaxInputNode(new PredicateSyntaxStrategy(predicate.WrapUserFunction(), transform.WrapUserFunction()), RegisterOutputAndDeferredInput)); } /// @@ -41,12 +41,12 @@ public IncrementalValuesProvider CreateSyntaxProvider(Func internal IncrementalValueProvider CreateSyntaxReceiverProvider(SyntaxContextReceiverCreator creator) { - var node = new SyntaxReceiverInputNode(creator, _registerOutput); + var node = new SyntaxInputNode(new SyntaxReceiverStrategy(creator, _registerOutput), RegisterOutputAndDeferredInput); _inputNodes.Add(node); return new IncrementalValueProvider(node); } - private void RegisterOutputAndDeferredInput(ISyntaxInputNode node, IIncrementalGeneratorOutputNode output) + private void RegisterOutputAndDeferredInput(SyntaxInputNode node, IIncrementalGeneratorOutputNode output) { _registerOutput(output); if (!_inputNodes.Contains(node)) diff --git a/src/Compilers/Core/Portable/SourceGeneration/SyntaxStore.cs b/src/Compilers/Core/Portable/SourceGeneration/SyntaxStore.cs new file mode 100644 index 0000000000000..0a04c950e7617 --- /dev/null +++ b/src/Compilers/Core/Portable/SourceGeneration/SyntaxStore.cs @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Threading; +using Microsoft.CodeAnalysis.Collections; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis +{ + internal sealed class SyntaxStore + { + private readonly StateTableStore _tables; + private readonly Compilation? _compilation; + internal static readonly SyntaxStore Empty = new SyntaxStore(StateTableStore.Empty, compilation: null); + + private SyntaxStore(StateTableStore tables, Compilation? compilation) + { + _tables = tables; + _compilation = compilation; + } + + public Builder ToBuilder(Compilation compilation, ImmutableArray syntaxInputNodes, bool enableTracking, CancellationToken cancellationToken) => new Builder(compilation, syntaxInputNodes, enableTracking, this, cancellationToken); + + public sealed class Builder + { + private readonly ImmutableDictionary.Builder _syntaxExceptions = ImmutableDictionary.CreateBuilder(); + private readonly StateTableStore.Builder _tableBuilder = new StateTableStore.Builder(); + private readonly Compilation _compilation; + private readonly ImmutableArray _syntaxInputNodes; + private readonly bool _enableTracking; + private readonly SyntaxStore _previous; + private readonly CancellationToken _cancellationToken; + + internal Builder(Compilation compilation, ImmutableArray syntaxInputNodes, bool enableTracking, SyntaxStore previousStore, CancellationToken cancellationToken) + { + _compilation = compilation; + _syntaxInputNodes = syntaxInputNodes; + _enableTracking = enableTracking; + _previous = previousStore; + _cancellationToken = cancellationToken; + } + + public IStateTable GetSyntaxInputTable(SyntaxInputNode syntaxInputNode, NodeStateTable syntaxTreeTable) + { + Debug.Assert(_syntaxInputNodes.Contains(syntaxInputNode)); + + // when we don't have a value for this node, we update all the syntax inputs at once + if (!_tableBuilder.Contains(syntaxInputNode)) + { + // CONSIDER: when the compilation is the same as previous, the syntax trees must also be the same. + // if we have a previous state table for a node, we can just short circuit knowing that it is up to date + // This step isn't part of the tree, so we can skip recording. + var compilationIsCached = _compilation == _previous._compilation; + + // get a builder for each input node + var syntaxInputBuilders = ArrayBuilder<(SyntaxInputNode node, ISyntaxInputBuilder builder)>.GetInstance(_syntaxInputNodes.Length); + foreach (var node in _syntaxInputNodes) + { + // We don't cache the tracked incremental steps in a manner that we can easily rehydrate between runs, + // so we disable the cached compilation perf optimization when incremental step tracking is enabled. + if (compilationIsCached && !_enableTracking && _previous._tables.TryGetValue(node, out var previousStateTable)) + { + _tableBuilder.SetTable(node, previousStateTable); + } + else + { + syntaxInputBuilders.Add((node, node.GetBuilder(_previous._tables, _enableTracking))); + } + } + + if (syntaxInputBuilders.Count > 0) + { + GeneratorRunStateTable.Builder temporaryRunStateBuilder = new GeneratorRunStateTable.Builder(_enableTracking); + + // at this point we need to grab the syntax trees from the new compilation, and optionally diff them against the old ones + NodeStateTable syntaxTreeState = syntaxTreeTable; + + // update each tree for the builders, sharing the semantic model + foreach (var (tree, state, syntaxTreeIndex, stepInfo) in syntaxTreeState) + { + var root = new Lazy(() => tree.GetRoot(_cancellationToken)); + var model = state != EntryState.Removed ? _compilation.GetSemanticModel(tree) : null; + for (int i = 0; i < syntaxInputBuilders.Count; i++) + { + try + { + _cancellationToken.ThrowIfCancellationRequested(); + syntaxInputBuilders[i].builder.VisitTree(root, state, model, _cancellationToken); + } + catch (UserFunctionException ufe) + { + // we're evaluating this node ahead of time, so we can't just throw the exception + // instead we'll hold onto it, and throw the exception when a downstream node actually + // attempts to read the value + _syntaxExceptions[syntaxInputBuilders[i].node] = ufe; + syntaxInputBuilders.RemoveAt(i); + i--; + } + } + } + + // save the updated inputs + foreach ((var node, ISyntaxInputBuilder builder) in syntaxInputBuilders) + { + builder.SaveStateAndFree(_tableBuilder); + Debug.Assert(_tableBuilder.Contains(node)); + } + } + syntaxInputBuilders.Free(); + } + + // if we don't have an entry for this node, it must have thrown an exception + if (!_tableBuilder.TryGetTable(syntaxInputNode, out var result)) + { + throw _syntaxExceptions[syntaxInputNode]; + } + return result; + } + + public SyntaxStore ToImmutable() + { + return new SyntaxStore(_tableBuilder.ToImmutable(), _compilation); + } + } + } +} diff --git a/src/Compilers/Core/Portable/SourceGeneration/UserFunction.cs b/src/Compilers/Core/Portable/SourceGeneration/UserFunction.cs index f38b4cc2864b2..72ee87619702f 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/UserFunction.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/UserFunction.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; -using Microsoft.CodeAnalysis.ErrorReporting; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { @@ -30,9 +30,7 @@ internal static Func WrapUserFunction> WrapUse return (input, token) => userFunction.WrapUserFunction()(input, token).ToImmutableArray(); } - internal static Action WrapUserAction(this Action userAction) + internal static Action WrapUserAction(this Action userAction) { - return input => + return (input, token) => { try { userAction(input); } -#pragma warning disable CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete; tracked by https://github.com/dotnet/roslyn/issues/58375 - catch (Exception e) when (FatalError.ReportIfNonFatalAndCatchUnlessCanceled(e)) -#pragma warning restore CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete + catch (Exception e) when (!ExceptionUtilities.IsCurrentOperationBeingCancelled(e, token)) { throw new UserFunctionException(e); } }; } - internal static Action WrapUserAction(this Action userAction) + internal static Action WrapUserAction(this Action userAction) { - return (input1, input2) => + return (input1, input2, token) => { try { userAction(input1, input2); } -#pragma warning disable CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete; tracked by https://github.com/dotnet/roslyn/issues/58375 - catch (Exception e) when (FatalError.ReportIfNonFatalAndCatchUnlessCanceled(e)) -#pragma warning restore CS0618 // ReportIfNonFatalAndCatchUnlessCanceled is obsolete + catch (Exception e) when (!ExceptionUtilities.IsCurrentOperationBeingCancelled(e, token)) { throw new UserFunctionException(e); } diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/CommonAttributeData.cs b/src/Compilers/Core/Portable/Symbols/Attributes/CommonAttributeData.cs index a2f65b10fc11d..c6434867f7a53 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/CommonAttributeData.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/CommonAttributeData.cs @@ -390,7 +390,7 @@ internal static void DecodeMethodImplAttribute new IParameterSymbol OriginalDefinition { get; } - - /// - /// True if the compiler will synthesize a null check for this parameter (the parameter is declared in source with a !! following the parameter name). - /// - bool IsNullChecked { get; } } } diff --git a/src/Compilers/Core/Portable/Syntax/InternalSyntax/SyntaxListBuilder`1.cs b/src/Compilers/Core/Portable/Syntax/InternalSyntax/SyntaxListBuilder`1.cs index 6008c6fd7215f..7592508c474dd 100644 --- a/src/Compilers/Core/Portable/Syntax/InternalSyntax/SyntaxListBuilder`1.cs +++ b/src/Compilers/Core/Portable/Syntax/InternalSyntax/SyntaxListBuilder`1.cs @@ -57,7 +57,11 @@ public void Clear() _builder.Clear(); } - public SyntaxListBuilder Add(TNode node) + /// + /// Adds to the end of this builder. No change happens if is + /// passed in. + /// + public SyntaxListBuilder Add(TNode? node) { _builder.Add(node); return this; diff --git a/src/Compilers/Core/Portable/Syntax/SyntaxNodeExtensions.cs b/src/Compilers/Core/Portable/Syntax/SyntaxNodeExtensions.cs index fee4ae0e0de3a..0003cf12531a5 100644 --- a/src/Compilers/Core/Portable/Syntax/SyntaxNodeExtensions.cs +++ b/src/Compilers/Core/Portable/Syntax/SyntaxNodeExtensions.cs @@ -29,12 +29,12 @@ public static partial class SyntaxNodeExtensions /// the same trivia with potentially rewritten sub structure. public static TRoot ReplaceSyntax( this TRoot root, - IEnumerable nodes, - Func computeReplacementNode, - IEnumerable tokens, - Func computeReplacementToken, - IEnumerable trivia, - Func computeReplacementTrivia) + IEnumerable? nodes, + Func? computeReplacementNode, + IEnumerable? tokens, + Func? computeReplacementToken, + IEnumerable? trivia, + Func? computeReplacementTrivia) where TRoot : SyntaxNode { return (TRoot)root.ReplaceCore( @@ -259,6 +259,7 @@ public static TRoot ReplaceTrivia(this TRoot root, SyntaxTrivia trivia, S /// The root node from which to remove a descendant node from. /// The node to remove. /// Options that determine how the node's trivia is treated. + /// New root or null if the root node itself is removed. public static TRoot? RemoveNode(this TRoot root, SyntaxNode node, SyntaxRemoveOptions options) diff --git a/src/Compilers/Core/Portable/Xml/XmlCharType.cs b/src/Compilers/Core/Portable/Xml/XmlCharType.cs index 79d9ff8d02304..abd100cb5e31f 100644 --- a/src/Compilers/Core/Portable/Xml/XmlCharType.cs +++ b/src/Compilers/Core/Portable/Xml/XmlCharType.cs @@ -474,7 +474,7 @@ internal static class XmlCharType 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0x00, 0x00, }; - private static byte charProperties(char i) + private static byte GetCharProperties(char i) { // The index entry, table, identifies the start of the appropriate 256-entry table within s_charProperties byte table = s_charPropertiesIndex[i >> innerSizeBits]; @@ -910,7 +910,7 @@ private static byte charProperties(char i) public static bool IsWhiteSpace(char ch) { - return (charProperties(ch) & fWhitespace) != 0; + return (GetCharProperties(ch) & fWhitespace) != 0; } public static bool IsExtender(char ch) @@ -920,7 +920,7 @@ public static bool IsExtender(char ch) public static bool IsNCNameSingleChar(char ch) { - return (charProperties(ch) & fNCNameSC) != 0; + return (GetCharProperties(ch) & fNCNameSC) != 0; } #if XML10_FIFTH_EDITION @@ -955,7 +955,7 @@ public static bool IsNCNameLowSurrogateChar(char lowChar) public static bool IsStartNCNameSingleChar(char ch) { - return (charProperties(ch) & fNCStartNameSC) != 0; + return (GetCharProperties(ch) & fNCStartNameSC) != 0; } #if XML10_FIFTH_EDITION @@ -982,7 +982,7 @@ public static bool IsStartNameSingleChar(char ch) public static bool IsCharData(char ch) { - return (charProperties(ch) & fCharData) != 0; + return (GetCharProperties(ch) & fCharData) != 0; } // [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] Section 2.3 of spec @@ -998,26 +998,26 @@ public static bool IsPubidChar(char ch) // TextChar = CharData - { 0xA, 0xD, '<', '&', ']' } internal static bool IsTextChar(char ch) { - return (charProperties(ch) & fText) != 0; + return (GetCharProperties(ch) & fText) != 0; } // AttrValueChar = CharData - { 0xA, 0xD, 0x9, '<', '>', '&', '\'', '"' } internal static bool IsAttributeValueChar(char ch) { - return (charProperties(ch) & fAttrValue) != 0; + return (GetCharProperties(ch) & fAttrValue) != 0; } // XML 1.0 Fourth Edition definitions // public static bool IsLetter(char ch) { - return (charProperties(ch) & fLetter) != 0; + return (GetCharProperties(ch) & fLetter) != 0; } // This method uses the XML 4th edition name character ranges public static bool IsNCNameCharXml4e(char ch) { - return (charProperties(ch) & fNCNameXml4e) != 0; + return (GetCharProperties(ch) & fNCNameXml4e) != 0; } // This method uses the XML 4th edition name character ranges @@ -1089,7 +1089,7 @@ internal static int IsOnlyWhitespaceWithPos(string str) { for (int i = 0; i < str.Length; i++) { - if ((charProperties(str[i]) & fWhitespace) == 0) + if ((GetCharProperties(str[i]) & fWhitespace) == 0) { return i; } @@ -1104,7 +1104,7 @@ internal static int IsOnlyCharData(string str) { for (int i = 0; i < str.Length; i++) { - if ((charProperties(str[i]) & fCharData) == 0) + if ((GetCharProperties(str[i]) & fCharData) == 0) { if (i + 1 >= str.Length || !(XmlCharType.IsHighSurrogate(str[i]) && XmlCharType.IsLowSurrogate(str[i + 1]))) { diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf index 6d6398cd05899..0fb46e1e726b6 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf @@ -256,12 +256,12 @@ <in-memory assembly> - < bellek içi derleme > + <bellek içi derleme> <in-memory module> - < bellek modülü > + <bellek modülü> diff --git a/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs new file mode 100644 index 0000000000000..887a382cc2d3d --- /dev/null +++ b/src/Compilers/Core/RebuildTest/BasicDeterministicKeyBuilderTests.cs @@ -0,0 +1,426 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using Roslyn.Test.Utilities; +using Xunit; +using Newtonsoft; +using Newtonsoft.Json.Linq; +using System.Linq; +using Newtonsoft.Json; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.PooledObjects; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.VisualBasic.UnitTests; +using System.Collections.Generic; +using System; + +namespace Microsoft.CodeAnalysis.Rebuild.UnitTests +{ + public sealed class BasicDeterministicKeyBuilderTests : DeterministicKeyBuilderTests + { + public static VisualBasicCompilationOptions BasicOptions { get; } = new VisualBasicCompilationOptions(OutputKind.ConsoleApplication, deterministic: true); + + protected override SyntaxTree ParseSyntaxTree(string content, string fileName, SourceHashAlgorithm hashAlgorithm, VisualBasicParseOptions? parseOptions) => + VisualBasicSyntaxTree.ParseText( + SourceText.From(content, checksumAlgorithm: hashAlgorithm, encoding: Encoding.UTF8), + path: fileName, + options: parseOptions); + + protected override VisualBasicCompilation CreateCompilation(SyntaxTree[] syntaxTrees, MetadataReference[]? references = null, VisualBasicCompilationOptions? options = null) + => VisualBasicCompilation.Create( + "test", + syntaxTrees, + references ?? NetCoreApp.References.ToArray(), + options: options ?? BasicOptions); + + protected override VisualBasicCompilationOptions GetCompilationOptions() => BasicOptions; + + protected override VisualBasicParseOptions GetParseOptions() => VisualBasicParseOptions.Default; + + private protected override DeterministicKeyBuilder GetDeterministicKeyBuilder() => VisualBasicDeterministicKeyBuilder.Instance; + + /// + /// This check monitors the set of properties and fields on the various option types + /// that contribute to the deterministic checksum of a . When + /// any of these tests change that means the new property or field needs to be evaluated + /// for inclusion into the checksum + /// + [Fact] + public void VerifyUpToDate() + { + verifyCount(11); + verifyCount(10); + verifyCount(62); + verifyCount(22); + + static void verifyCount(int expected) + { + var type = typeof(T); + var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance; + var fields = type.GetFields(flags); + var properties = type.GetProperties(flags); + var count = fields.Length + properties.Length; + Assert.Equal(expected, count); + } + } + + + [Theory] + [InlineData(@"hello world")] + [InlineData(@"just need some text here")] + [InlineData(@"yet another case")] + public void ContentInAdditionalText(string content) + { + var syntaxTree = VisualBasicSyntaxTree.ParseText( + "", + path: "file.vb"); + var additionalText = new TestAdditionalText(content, Encoding.UTF8, path: "file.txt", HashAlgorithm); + var contentChecksum = GetChecksum(additionalText.GetText()!); + + var compilation = VisualBasicCompilation.Create( + "test", + new[] { syntaxTree }, + NetCoreApp.References, + options: BasicOptions); + var key = compilation.GetDeterministicKey(additionalTexts: ImmutableArray.Create(additionalText)); + var expected = @$" +""additionalTexts"": [ + {{ + ""fileName"": ""file.txt"", + ""text"": {{ + ""checksum"": ""{contentChecksum}"", + ""checksumAlgorithm"": ""Sha256"", + ""encodingName"": ""Unicode (UTF-8)"" + }} + }} +]"; + AssertJsonSection(expected, key, "additionalTexts"); + } + + [Fact] + public void GlobalImports() + { + var syntaxTree = VisualBasicSyntaxTree.ParseText( + "", + path: "file.vb"); + + var options = BasicOptions + .WithGlobalImports(new[] + { + GlobalImport.Parse(@""), + GlobalImport.Parse("System.Xml") + }); + var compilation = VisualBasicCompilation.Create( + "test", + new[] { syntaxTree }, + NetCoreApp.References, + options: options); + var key = compilation.GetDeterministicKey(); + var expected = @" +""globalImports"": [ + { + ""name"": """", + ""isXmlClause"": true + }, + { + ""name"": ""System.Xml"", + ""isXmlClause"": false + } +]"; + + AssertJsonSection(expected, key, "compilation.options.globalImports"); + } + + [Theory] + [CombinatorialData] + public void BasicParseOptionsLanguageVersion(LanguageVersion languageVersion) + { + var parseOptions = VisualBasicParseOptions.Default.WithLanguageVersion(languageVersion); + var obj = GetParseOptionsValue(parseOptions); + var effective = languageVersion.MapSpecifiedToEffectiveVersion(); + + Assert.Equal(effective.ToString(), obj.Value("languageVersion")); + Assert.Equal(languageVersion.ToString(), obj.Value("specifiedLanguageVersion")); + } + + [Fact] + public void BasicPreprocessorSymbols() + { + assert(@"{}"); + + assert(@" +{ + ""DEBUG"": null +}", ("DEBUG", null)); + + + assert(@" +{ + ""DEBUG"": null, + ""TRACE"": null +}", ("TRACE", null), ("DEBUG", null)); + + assert(@" +{ + ""DEBUG"": ""13"", + ""TRACE"": ""42"" +}", ("TRACE", 42), ("DEBUG", 13)); + + assert(@" +{ + ""DEBUG"": ""4.2"", + ""TRACE"": true +}", ("TRACE", true), ("DEBUG", 4.2)); + + + void assert(string? expected, params (string Key, object? Value)[] values) + { + var parseOptions = VisualBasicParseOptions.Default.WithPreprocessorSymbols(values.Select(x => new KeyValuePair(x.Key, x.Value!))); + var obj = GetParseOptionsValue(parseOptions); + AssertJsonCore(expected, obj.Value("preprocessorSymbols")?.ToString(Formatting.Indented)); + } + } + + [ConditionalTheory(typeof(WindowsOnly))] + [InlineData(@"c:\src\code.vb", @"c:\src", null)] + [InlineData(@"d:\src\code.vb", @"d:\src\", @"/pathmap:d:\=c:\")] + [InlineData(@"e:\long\path\src\code.vb", @"e:\long\path\src\", @"/pathmap:e:\long\path\=c:\")] + public void BasicPathMapWindows(string filePath, string workingDirectory, string? pathMap) + { + var args = new List(new[] { filePath, "/nostdlib", "/vbruntime-", "/langversion:15" }); + if (pathMap is not null) + { + args.Add(pathMap); + } + + var compiler = new MockVisualBasicCompiler( + baseDirectory: workingDirectory, + args.ToArray()); + compiler.FileSystem = TestableFileSystem.CreateForFiles((filePath, new TestableFile("hello"))); + AssertSyntaxTreePathMap(@" +[ + { + ""fileName"": ""c:\\src\\code.vb"", + ""text"": { + ""checksum"": ""2cf24dba5fb0a3e26e83b2ac5b9e29e1b161e5c1fa7425e7343362938b9824"", + ""checksumAlgorithm"": ""Sha256"", + ""encodingName"": ""Unicode (UTF-8)"" + }, + ""parseOptions"": { + ""kind"": ""Regular"", + ""specifiedKind"": ""Regular"", + ""documentationMode"": ""None"", + ""language"": ""Visual Basic"", + ""features"": {}, + ""languageVersion"": ""VisualBasic15"", + ""specifiedLanguageVersion"": ""VisualBasic15"", + ""preprocessorSymbols"": { + ""TARGET"": ""exe"", + ""VBC_VER"": ""16.9"" + } + } + } +] +", compiler); + } + + [Fact] + public void MetadataReferenceCompilation() + { + var utilCompilation = VisualBasicCompilation.Create( + assemblyName: "util", + syntaxTrees: new[] { VisualBasicSyntaxTree.ParseText(@"// this is a comment", VisualBasicParseOptions.Default.WithLanguageVersion(LanguageVersion.VisualBasic15)) }, + options: new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, deterministic: true)); + var compilation = CreateCompilation( + Array.Empty(), + references: new[] { utilCompilation.ToMetadataReference() }); + var references = GetReferenceValues(compilation); + var compilationValue = references.Values().Single()!; + var expected = @" +{ + ""compilation"": { + ""publicKey"": """", + ""options"": { + ""outputKind"": ""DynamicallyLinkedLibrary"", + ""moduleName"": null, + ""scriptClassName"": ""Script"", + ""mainTypeName"": null, + ""cryptoPublicKey"": """", + ""cryptoKeyFile"": null, + ""delaySign"": null, + ""publicSign"": false, + ""checkOverflow"": true, + ""platform"": ""AnyCpu"", + ""optimizationLevel"": ""Debug"", + ""generalDiagnosticOption"": ""Default"", + ""warningLevel"": 1, + ""deterministic"": true, + ""debugPlusMode"": false, + ""referencesSupersedeLowerVersions"": false, + ""reportSuppressedDiagnostics"": false, + ""nullableContextOptions"": ""Disable"", + ""specificDiagnosticOptions"": [], + ""localtime"": null, + ""rootNamespace"": """", + ""optionStrict"": ""Off"", + ""optionInfer"": true, + ""optionExplicit"": true, + ""optionCompareText"": false, + ""embedVbCoreRuntime"": false, + ""globalImports"": [], + ""parseOptions"": null + }, + ""syntaxTrees"": [ + { + ""fileName"": """", + ""text"": { + ""checksum"": ""053e2a4aa83f63193c1069d651b63bedca1e97"", + ""checksumAlgorithm"": ""Sha1"", + ""encodingName"": null + }, + ""parseOptions"": { + ""kind"": ""Regular"", + ""specifiedKind"": ""Regular"", + ""documentationMode"": ""Parse"", + ""language"": ""Visual Basic"", + ""features"": {}, + ""languageVersion"": ""VisualBasic15"", + ""specifiedLanguageVersion"": ""VisualBasic15"", + ""preprocessorSymbols"": { + ""_MYTYPE"": ""Empty"" + } + } + } + ] + } +} +"; + + AssertJson(expected, compilationValue.ToString(Formatting.Indented), "toolsVersions", "references", "extensions"); + } + + [Fact] + public void FeatureFlag() + { + var compiler = TestableCompiler.CreateBasicNetCoreApp("test.vb", @"-t:library", "-nologo", "-features:debug-determinism", "-deterministic", @"-define:_MYTYPE=""Empty""", "-debug:portable"); + var sourceFile = compiler.AddSourceFile("test.vb", @"' this is a test file"); + compiler.AddOutputFile("test.dll"); + var pdbFile = compiler.AddOutputFile("test.pdb"); + var keyFile = compiler.AddOutputFile("test.dll.key"); + var (result, output) = compiler.Run(); + Assert.True(string.IsNullOrEmpty(output)); + Assert.Equal(0, result); + + var json = Encoding.UTF8.GetString(keyFile.Contents.ToArray()); + var expected = @$" +{{ + ""compilation"": {{ + ""publicKey"": """", + ""options"": {{ + ""outputKind"": ""DynamicallyLinkedLibrary"", + ""moduleName"": ""test.dll"", + ""scriptClassName"": ""Script"", + ""mainTypeName"": null, + ""cryptoPublicKey"": """", + ""cryptoKeyFile"": null, + ""delaySign"": null, + ""publicSign"": false, + ""checkOverflow"": true, + ""platform"": ""AnyCpu"", + ""optimizationLevel"": ""Debug"", + ""generalDiagnosticOption"": ""Default"", + ""warningLevel"": 1, + ""deterministic"": true, + ""debugPlusMode"": false, + ""referencesSupersedeLowerVersions"": false, + ""reportSuppressedDiagnostics"": false, + ""nullableContextOptions"": ""Disable"", + ""specificDiagnosticOptions"": [], + ""localtime"": null, + ""rootNamespace"": """", + ""optionStrict"": ""Off"", + ""optionInfer"": false, + ""optionExplicit"": true, + ""optionCompareText"": false, + ""embedVbCoreRuntime"": false, + ""globalImports"": [], + ""parseOptions"": {{ + ""kind"": ""Regular"", + ""specifiedKind"": ""Regular"", + ""documentationMode"": ""None"", + ""language"": ""Visual Basic"", + ""features"": {{ + ""debug-determinism"": ""true"" + }}, + ""languageVersion"": ""VisualBasic16_9"", + ""specifiedLanguageVersion"": ""Default"", + ""preprocessorSymbols"": {{ + ""TARGET"": ""library"", + ""VBC_VER"": ""16.9"", + ""_MYTYPE"": ""Empty"" + }} + }} + }}, + ""syntaxTrees"": [ + {{ + ""fileName"": ""{Roslyn.Utilities.JsonWriter.EscapeString(sourceFile.FilePath)}"", + ""text"": {{ + ""checksum"": ""8f9cdc9e727da9f8f0569be3dc606bfc6c1a1b13444e18c95eefb73810bbf1"", + ""checksumAlgorithm"": ""Sha256"", + ""encodingName"": ""Unicode (UTF-8)"" + }}, + ""parseOptions"": {{ + ""kind"": ""Regular"", + ""specifiedKind"": ""Regular"", + ""documentationMode"": ""None"", + ""language"": ""Visual Basic"", + ""features"": {{ + ""debug-determinism"": ""true"" + }}, + ""languageVersion"": ""VisualBasic16_9"", + ""specifiedLanguageVersion"": ""Default"", + ""preprocessorSymbols"": {{ + ""TARGET"": ""library"", + ""VBC_VER"": ""16.9"", + ""_MYTYPE"": ""Empty"" + }} + }} + }} + ] + }}, + ""additionalTexts"": [], + ""analyzers"": [], + ""generators"": [], + ""emitOptions"": {{ + ""emitMetadataOnly"": false, + ""tolerateErrors"": false, + ""includePrivateMembers"": true, + ""instrumentationKinds"": [], + ""subsystemVersion"": {{ + ""major"": 0, + ""minor"": 0 + }}, + ""fileAlignment"": 0, + ""highEntropyVirtualAddressSpace"": false, + ""baseAddress"": ""0"", + ""debugInformationFormat"": ""PortablePdb"", + ""outputNameOverride"": ""test.dll"", + ""pdbFilePath"": ""{Roslyn.Utilities.JsonWriter.EscapeString(pdbFile.FilePath)}"", + ""pdbChecksumAlgorithm"": ""SHA256"", + ""runtimeMetadataVersion"": null, + ""defaultSourceFileEncoding"": null, + ""fallbackSourceFileEncoding"": null + }} +}} +"; + AssertJson(expected, json, "toolsVersions", "references", "extensions"); + } + } +} diff --git a/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs new file mode 100644 index 0000000000000..59a433c74987d --- /dev/null +++ b/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs @@ -0,0 +1,589 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; +using Newtonsoft; +using Newtonsoft.Json.Linq; +using System.Linq; +using Newtonsoft.Json; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.PooledObjects; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.VisualBasic.UnitTests; +using System; +using System.IO; +using System.Collections.Generic; +using System.Security.Cryptography; +using Microsoft.CodeAnalysis.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Rebuild.UnitTests +{ + public sealed class CSharpDeterministicKeyBuilderTests : DeterministicKeyBuilderTests + { + public static CSharpCompilationOptions Options { get; } = new CSharpCompilationOptions(OutputKind.ConsoleApplication, deterministic: true); + + protected override SyntaxTree ParseSyntaxTree(string content, string fileName, SourceHashAlgorithm hashAlgorithm, CSharpParseOptions? parseOptions) => + CSharpTestBase.Parse( + content, + filename: fileName, + checksumAlgorithm: hashAlgorithm, + encoding: Encoding.UTF8, + options: parseOptions); + + protected override CSharpCompilation CreateCompilation(SyntaxTree[] syntaxTrees, MetadataReference[]? references = null, CSharpCompilationOptions? options = null) => + CSharpCompilation.Create( + "test", + syntaxTrees, + references ?? NetCoreApp.References.ToArray(), + options ?? Options); + + private protected override DeterministicKeyBuilder GetDeterministicKeyBuilder() => CSharpDeterministicKeyBuilder.Instance; + + protected override CSharpCompilationOptions GetCompilationOptions() => Options; + + protected override CSharpParseOptions GetParseOptions() => CSharpParseOptions.Default; + + /// + /// This check monitors the set of properties and fields on the various option types + /// that contribute to the deterministic checksum of a . When + /// any of these tests change that means the new property or field needs to be evaluated + /// for inclusion into the checksum + /// + [Fact] + public void VerifyUpToDate() + { + verifyCount(11); + verifyCount(10); + verifyCount(62); + verifyCount(9); + + static void verifyCount(int expected) + { + var type = typeof(T); + var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance; + var fields = type.GetFields(flags); + var properties = type.GetProperties(flags); + var count = fields.Length + properties.Length; + Assert.Equal(expected, count); + } + } + + [Fact] + public void Simple() + { + var compilation = CSharpTestBase.CreateCompilation( + @"System.Console.WriteLine(""Hello World"");", + targetFramework: TargetFramework.NetCoreApp, + options: Options); + + var key = compilation.GetDeterministicKey(options: DeterministicKeyOptions.IgnoreToolVersions); + AssertJson(@" +{ + ""compilation"": { + ""toolsVersions"": {}, + ""publicKey"": """", + ""options"": { + ""outputKind"": ""ConsoleApplication"", + ""moduleName"": null, + ""scriptClassName"": ""Script"", + ""mainTypeName"": null, + ""cryptoPublicKey"": """", + ""cryptoKeyFile"": null, + ""delaySign"": null, + ""publicSign"": false, + ""checkOverflow"": false, + ""platform"": ""AnyCpu"", + ""optimizationLevel"": ""Debug"", + ""generalDiagnosticOption"": ""Default"", + ""warningLevel"": 4, + ""deterministic"": true, + ""debugPlusMode"": false, + ""referencesSupersedeLowerVersions"": false, + ""reportSuppressedDiagnostics"": false, + ""nullableContextOptions"": ""Disable"", + ""specificDiagnosticOptions"": [], + ""localtime"": null, + ""unsafe"": false, + ""topLevelBinderFlags"": ""None"", + ""usings"": [] + }, + ""syntaxTrees"": [ + { + ""fileName"": """", + ""text"": { + ""checksum"": ""1b565cf6f2d814a4dc37ce578eda05fe0614f3d"", + ""checksumAlgorithm"": ""Sha1"", + ""encodingName"": ""Unicode (UTF-8)"" + }, + ""parseOptions"": { + ""kind"": ""Regular"", + ""specifiedKind"": ""Regular"", + ""documentationMode"": ""Parse"", + ""language"": ""C#"", + ""features"": {}, + ""languageVersion"": ""Preview"", + ""specifiedLanguageVersion"": ""Preview"", + ""preprocessorSymbols"": [] + } + } + ] + }, + ""additionalTexts"": [], + ""analyzers"": [], + ""generators"": [], + ""emitOptions"": null +} +", key); + } + + [Theory] + [CombinatorialData] + public void SyntaxTreeFilePath(bool ignoreFilePaths) + { + var path = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? @"c:\code\file.cs" + : @"/code/file.cs"; + var (expectedPath, options) = ignoreFilePaths + ? ("file.cs", DeterministicKeyOptions.IgnorePaths) + : (path, DeterministicKeyOptions.Default); + + var source = CSharpTestBase.Parse( + @"System.Console.WriteLine(""Hello World"");", + filename: path, + checksumAlgorithm: SourceHashAlgorithm.Sha1); + var compilation = CSharpTestBase.CreateCompilation(source); + var key = compilation.GetDeterministicKey(options: options); + var expected = @$" +""syntaxTrees"": [ + {{ + ""fileName"": ""{Roslyn.Utilities.JsonWriter.EscapeString(expectedPath)}"", + ""text"": {{ + ""checksum"": ""1b565cf6f2d814a4dc37ce578eda05fe0614f3d"", + ""checksumAlgorithm"": ""Sha1"", + ""encodingName"": ""Unicode (UTF-8)"" + }}, + ""parseOptions"": {{ + ""kind"": ""Regular"", + ""specifiedKind"": ""Regular"", + ""documentationMode"": ""Parse"", + ""language"": ""C#"", + ""features"": {{}}, + ""languageVersion"": ""Preview"", + ""specifiedLanguageVersion"": ""Preview"", + ""preprocessorSymbols"": [] + }} + }} +]"; + AssertJsonSection(expected, key, "compilation.syntaxTrees"); + } + + [Theory] + [InlineData(@"hello world")] + [InlineData(@"just need some text here")] + [InlineData(@"yet another case")] + public void ContentInAdditionalText(string content) + { + var syntaxTree = CSharpTestBase.Parse( + "", + filename: "file.cs", + checksumAlgorithm: HashAlgorithm); + var additionalText = new TestAdditionalText(content, Encoding.UTF8, path: "file.txt", HashAlgorithm); + var contentChecksum = GetChecksum(additionalText.GetText()!); + + var compilation = CSharpTestBase.CreateCompilation(syntaxTree); + var key = compilation.GetDeterministicKey(additionalTexts: ImmutableArray.Create(additionalText)); + var expected = @$" +""additionalTexts"": [ + {{ + ""fileName"": ""file.txt"", + ""text"": {{ + ""checksum"": ""{contentChecksum}"", + ""checksumAlgorithm"": ""Sha256"", + ""encodingName"": ""Unicode (UTF-8)"" + }} + }} +]"; + AssertJsonSection(expected, key, "additionalTexts"); + } + + /// + /// Generally tests omit the tools versions in the Json output for simplicity but need at least + /// one test that verifies we're actually encoding them. + /// + [Fact] + public void ToolsVersion() + { + var compilation = CSharpTestBase.CreateCompilation( + @"System.Console.WriteLine(""Hello World"");", + targetFramework: TargetFramework.NetCoreApp, + options: Options); + + var key = compilation.GetDeterministicKey(options: DeterministicKeyOptions.Default); + + var compilerVersion = typeof(Compilation).Assembly.GetCustomAttribute()?.InformationalVersion; + var runtimeVersion = typeof(object).Assembly.GetCustomAttribute()?.InformationalVersion; + + AssertJson($@" +{{ + ""compilation"": {{ + ""toolsVersions"": {{ + ""compilerVersion"": ""{compilerVersion}"", + ""runtimeVersion"": ""{runtimeVersion}"", + ""frameworkDescription"": ""{RuntimeInformation.FrameworkDescription}"", + ""osDescription"": ""{RuntimeInformation.OSDescription}"" + }}, + ""publicKey"": """", + ""options"": {{ + ""outputKind"": ""ConsoleApplication"", + ""moduleName"": null, + ""scriptClassName"": ""Script"", + ""mainTypeName"": null, + ""cryptoPublicKey"": """", + ""cryptoKeyFile"": null, + ""delaySign"": null, + ""publicSign"": false, + ""checkOverflow"": false, + ""platform"": ""AnyCpu"", + ""optimizationLevel"": ""Debug"", + ""generalDiagnosticOption"": ""Default"", + ""warningLevel"": 4, + ""deterministic"": true, + ""debugPlusMode"": false, + ""referencesSupersedeLowerVersions"": false, + ""reportSuppressedDiagnostics"": false, + ""nullableContextOptions"": ""Disable"", + ""specificDiagnosticOptions"": [], + ""localtime"": null, + ""unsafe"": false, + ""topLevelBinderFlags"": ""None"", + ""usings"": [] + }} + }}, + ""additionalTexts"": [], + ""analyzers"": [], + ""generators"": [], + ""emitOptions"": null +}} +", key, "references", "syntaxTrees", "extensions"); + } + + [Theory] + [CombinatorialData] + public void CSharpCompilationOptionsCombination(bool @unsafe, NullableContextOptions nullableContextOptions) + { + foreach (BinderFlags binderFlags in Enum.GetValues(typeof(BinderFlags))) + { + var options = Options + .WithAllowUnsafe(@unsafe) + .WithTopLevelBinderFlags(binderFlags) + .WithNullableContextOptions(nullableContextOptions); + + var value = GetCompilationOptionsValue(options); + Assert.Equal(@unsafe, value.Value("unsafe")); + Assert.Equal(binderFlags.ToString(), value.Value("topLevelBinderFlags")); + Assert.Equal(nullableContextOptions.ToString(), value.Value("nullableContextOptions")); + } + } + + [Fact] + public void CSharpCompilationOptionsGlobalUsings() + { + assert(@" +[ + ""System"", + ""System.Xml"" +] +", "System", "System.Xml"); + + assert(@" +[ + ""System.Xml"", + ""System"" +] +", "System.Xml", "System"); + + assert(@" +[ + ""System.Xml"" +] +", "System.Xml"); + + void assert(string expected, params string[] usings) + { + var options = Options.WithUsings(usings); + var value = GetCompilationOptionsValue(options); + var actual = value["usings"]?.ToString(Formatting.Indented); + AssertJsonCore(expected, actual); + } + } + + [Theory] + [CombinatorialData] + public void CSharpParseOptionsLanguageVersion(LanguageVersion languageVersion) + { + var parseOptions = CSharpParseOptions.Default.WithLanguageVersion(languageVersion); + var obj = GetParseOptionsValue(parseOptions); + var effective = languageVersion.MapSpecifiedToEffectiveVersion(); + + Assert.Equal(effective.ToString(), obj.Value("languageVersion")); + Assert.Equal(languageVersion.ToString(), obj.Value("specifiedLanguageVersion")); + } + + [Fact] + public void CSharpParseOptionsPreprocessorSymbols() + { + assert(@"[]"); + + assert(@" +[ + ""DEBUG"" +]", "DEBUG"); + + assert(@" +[ + ""DEBUG"", + ""TRACE"" +]", "DEBUG", "TRACE"); + + + assert(@" +[ + ""DEBUG"", + ""TRACE"" +]", "TRACE", "DEBUG"); + + + void assert(string expected, params string[] values) + { + var parseOptions = CSharpParseOptions.Default.WithPreprocessorSymbols(values); + var obj = GetParseOptionsValue(parseOptions); + AssertJsonCore(expected, obj.Value("preprocessorSymbols")?.ToString(Formatting.Indented)); + } + } + + [ConditionalTheory(typeof(WindowsOnly))] + [InlineData(@"c:\src\code.cs", @"c:\src", null)] + [InlineData(@"d:\src\code.cs", @"d:\src\", @"/pathmap:d:\=c:\")] + [InlineData(@"e:\long\path\src\code.cs", @"e:\long\path\src\", @"/pathmap:e:\long\path\=c:\")] + public void CSharpPathMapWindows(string filePath, string workingDirectory, string? pathMap) + { + var args = new List(new[] { filePath, "/nostdlib", "/langversion:9" }); + if (pathMap is not null) + { + args.Add(pathMap); + } + + var compiler = new MockCSharpCompiler( + null, + workingDirectory: workingDirectory, + args.ToArray()); + compiler.FileSystem = TestableFileSystem.CreateForFiles((filePath, new TestableFile("hello"))); + AssertSyntaxTreePathMap(@" +[ + { + ""fileName"": ""c:\\src\\code.cs"", + ""text"": { + ""checksum"": ""2cf24dba5fb0a3e26e83b2ac5b9e29e1b161e5c1fa7425e7343362938b9824"", + ""checksumAlgorithm"": ""Sha256"", + ""encodingName"": ""Unicode (UTF-8)"" + }, + ""parseOptions"": { + ""kind"": ""Regular"", + ""specifiedKind"": ""Regular"", + ""documentationMode"": ""None"", + ""language"": ""C#"", + ""features"": {}, + ""languageVersion"": ""CSharp9"", + ""specifiedLanguageVersion"": ""CSharp9"", + ""preprocessorSymbols"": [] + } + } +] +", compiler); + } + + [ConditionalFact(typeof(WindowsOnly))] + public void CSharpPublicKey() + { + var keyFilePath = @"c:\windows\key.snk"; + var publicKey = TestResources.General.snPublicKey; + var publicKeyStr = DeterministicKeyBuilder.EncodeByteArrayValue(publicKey); + var fileSystem = new TestStrongNameFileSystem(); + fileSystem.ReadAllBytesFunc = _ => publicKey; + var options = Options + .WithCryptoKeyFile(keyFilePath) + .WithStrongNameProvider(new DesktopStrongNameProvider(default, fileSystem)); + var compilation = CreateCompilation(new SyntaxTree[] { }, options: options); + var obj = GetCompilationValue(compilation); + Assert.Equal(publicKeyStr, obj.Value("publicKey")); + } + + [Fact] + public void MetadataReferenceCompilation() + { + var utilCompilation = CSharpCompilation.Create( + assemblyName: "util", + syntaxTrees: new[] { CSharpSyntaxTree.ParseText(@"// this is a comment", CSharpParseOptions.Default.WithLanguageVersion(CSharp.LanguageVersion.CSharp10)) }, + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, deterministic: true)); + var compilation = CreateCompilation( + Array.Empty(), + references: new[] { utilCompilation.ToMetadataReference() }); + var references = GetReferenceValues(compilation); + var compilationValue = references.Values().Single()!; + var expected = @" +{ + ""compilation"": { + ""publicKey"": """", + ""options"": { + ""outputKind"": ""DynamicallyLinkedLibrary"", + ""moduleName"": null, + ""scriptClassName"": ""Script"", + ""mainTypeName"": null, + ""cryptoPublicKey"": """", + ""cryptoKeyFile"": null, + ""delaySign"": null, + ""publicSign"": false, + ""checkOverflow"": false, + ""platform"": ""AnyCpu"", + ""optimizationLevel"": ""Debug"", + ""generalDiagnosticOption"": ""Default"", + ""warningLevel"": 4, + ""deterministic"": true, + ""debugPlusMode"": false, + ""referencesSupersedeLowerVersions"": false, + ""reportSuppressedDiagnostics"": false, + ""nullableContextOptions"": ""Disable"", + ""specificDiagnosticOptions"": [], + ""localtime"": null, + ""unsafe"": false, + ""topLevelBinderFlags"": ""None"", + ""usings"": [] + }, + ""syntaxTrees"": [ + { + ""fileName"": """", + ""text"": { + ""checksum"": ""053e2a4aa83f63193c1069d651b63bedca1e97"", + ""checksumAlgorithm"": ""Sha1"", + ""encodingName"": null + }, + ""parseOptions"": { + ""kind"": ""Regular"", + ""specifiedKind"": ""Regular"", + ""documentationMode"": ""Parse"", + ""language"": ""C#"", + ""features"": {}, + ""languageVersion"": ""CSharp10"", + ""specifiedLanguageVersion"": ""CSharp10"", + ""preprocessorSymbols"": [] + } + } + ] + } +} +"; + + AssertJson(expected, compilationValue.ToString(Formatting.Indented), "toolsVersions", "references", "extensions"); + } + + [Fact] + public void FeatureFlag() + { + var compiler = TestableCompiler.CreateCSharpNetCoreApp("test.cs", @"-t:library", "-nologo", "-features:debug-determinism", "-deterministic", "-debug:portable"); + var sourceFile = compiler.AddSourceFile("test.cs", @"// this is a test file"); + compiler.AddOutputFile("test.dll"); + var pdbFile = compiler.AddOutputFile("test.pdb"); + var keyFile = compiler.AddOutputFile("test.dll.key"); + var (result, output) = compiler.Run(); + Assert.True(string.IsNullOrEmpty(output)); + Assert.Equal(0, result); + + var json = Encoding.UTF8.GetString(keyFile.Contents.ToArray()); + var expected = @$" +{{ + ""compilation"": {{ + ""publicKey"": """", + ""options"": {{ + ""outputKind"": ""DynamicallyLinkedLibrary"", + ""moduleName"": ""test.dll"", + ""scriptClassName"": ""Script"", + ""mainTypeName"": null, + ""cryptoPublicKey"": """", + ""cryptoKeyFile"": null, + ""delaySign"": null, + ""publicSign"": false, + ""checkOverflow"": false, + ""platform"": ""AnyCpu"", + ""optimizationLevel"": ""Debug"", + ""generalDiagnosticOption"": ""Default"", + ""warningLevel"": 4, + ""deterministic"": true, + ""debugPlusMode"": false, + ""referencesSupersedeLowerVersions"": false, + ""reportSuppressedDiagnostics"": false, + ""nullableContextOptions"": ""Disable"", + ""specificDiagnosticOptions"": [], + ""localtime"": null, + ""unsafe"": false, + ""topLevelBinderFlags"": ""None"", + ""usings"": [] + }}, + ""syntaxTrees"": [ + {{ + ""fileName"": ""{Roslyn.Utilities.JsonWriter.EscapeString(sourceFile.FilePath)}"", + ""text"": {{ + ""checksum"": ""2326e849c5bb80ded5ef51743244896b812672aa03119ee8788cdc3b356f88"", + ""checksumAlgorithm"": ""Sha256"", + ""encodingName"": ""Unicode (UTF-8)"" + }}, + ""parseOptions"": {{ + ""kind"": ""Regular"", + ""specifiedKind"": ""Regular"", + ""documentationMode"": ""None"", + ""language"": ""C#"", + ""features"": {{ + ""debug-determinism"": ""true"" + }}, + ""languageVersion"": ""CSharp10"", + ""specifiedLanguageVersion"": ""Default"", + ""preprocessorSymbols"": [] + }} + }} + ] + }}, + ""additionalTexts"": [], + ""analyzers"": [], + ""generators"": [], + ""emitOptions"": {{ + ""emitMetadataOnly"": false, + ""tolerateErrors"": false, + ""includePrivateMembers"": true, + ""instrumentationKinds"": [], + ""subsystemVersion"": {{ + ""major"": 0, + ""minor"": 0 + }}, + ""fileAlignment"": 0, + ""highEntropyVirtualAddressSpace"": false, + ""baseAddress"": ""0"", + ""debugInformationFormat"": ""PortablePdb"", + ""outputNameOverride"": ""test.dll"", + ""pdbFilePath"": ""{Roslyn.Utilities.JsonWriter.EscapeString(pdbFile.FilePath)}"", + ""pdbChecksumAlgorithm"": ""SHA256"", + ""runtimeMetadataVersion"": null, + ""defaultSourceFileEncoding"": null, + ""fallbackSourceFileEncoding"": null + }} +}}"; + AssertJson(expected, json, "toolsVersions", "references", "extensions"); + } + } +} diff --git a/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.Helpers.cs b/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.Helpers.cs new file mode 100644 index 0000000000000..101aa11f3b4a1 --- /dev/null +++ b/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.Helpers.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.VisualBasic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Roslyn.Test.Utilities; +using Roslyn.Test.Utilities.TestGenerators; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Rebuild.UnitTests +{ + public partial class DeterministicKeyBuilderTests + { + private sealed class Analyzer : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics => throw new NotImplementedException(); + + public override void Initialize(AnalysisContext context) => throw new NotImplementedException(); + } + + private sealed class Analyzer2 : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics => throw new NotImplementedException(); + + public override void Initialize(AnalysisContext context) => throw new NotImplementedException(); + } + + private sealed class Generator : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) => throw new NotImplementedException(); + + public void Initialize(GeneratorInitializationContext context) => throw new NotImplementedException(); + } + + private sealed class Generator2 : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) => throw new NotImplementedException(); + + public void Initialize(GeneratorInitializationContext context) => throw new NotImplementedException(); + } + } +} diff --git a/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.cs new file mode 100644 index 0000000000000..b32004b10968a --- /dev/null +++ b/src/Compilers/Core/RebuildTest/DeterministicKeyBuilderTests.cs @@ -0,0 +1,827 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.VisualBasic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Roslyn.Test.Utilities; +using Roslyn.Test.Utilities.TestGenerators; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Rebuild.UnitTests +{ + public abstract partial class DeterministicKeyBuilderTests + where TCompilation : Compilation + where TCompilationOptions : CompilationOptions + where TParseOptions : ParseOptions + { + private static readonly char[] s_trimChars = { ' ', '\n', '\r' }; + + public static EmitOptions EmitOptions { get; } = new(); + public static SourceHashAlgorithm HashAlgorithm { get; } = SourceHashAlgorithm.Sha256; + public static SourceHashAlgorithm[] HashAlgorithms { get; } = new[] + { + SourceHashAlgorithm.Sha1, + SourceHashAlgorithm.Sha256 + }; + + protected static void AssertJson( + string expected, + string actual) => AssertJson(expected, actual, "references", "extensions"); + + protected static void AssertJson( + string expected, + string actual, + params string[] ignoreSections) + { + var json = JObject.Parse(actual); + if (ignoreSections.Length > 0) + { + json + .Descendants() + .OfType() + .Where(x => ignoreSections.Contains(x.Name)) + .ToList() + .ForEach(x => x.Remove()); + } + + actual = json.ToString(Formatting.Indented); + expected = JObject.Parse(expected).ToString(Formatting.Indented); + AssertJsonCore(expected, actual); + } + + protected static void AssertJsonSection( + string expected, + string actual, + string sectionName, + params string[] ignoreProperties) + { + var property = GetJsonProperty(actual, sectionName, ignoreProperties); + AssertJsonCore(expected, property.ToString(Formatting.Indented)); + } + + protected static void AssertJsonCore(string? expected, string? actual) + { + expected = expected?.Trim(s_trimChars); + actual = actual?.Trim(s_trimChars); + Assert.Equal(expected, actual); + } + + private protected static void AssertSyntaxTreePathMap(string? expected, CommonCompiler compiler) + { + Assert.Empty(compiler.Arguments.Errors); + + var writer = new StringWriter(); + var compilation = compiler.CreateCompilation( + writer, + touchedFilesLogger: null, + errorLoggerOpt: null, + analyzerConfigOptions: default, + globalConfigOptions: default); + AssertEx.NotNull(compilation); + Assert.Empty(writer.GetStringBuilder().ToString()); + var obj = GetSyntaxTreeValues(compilation, compiler.Arguments.PathMap); + AssertJsonCore(expected, obj.ToString(Formatting.Indented)); + } + + protected static JProperty GetJsonProperty( + string json, + string sectionName, + params string[] ignoreProperties) + { + var lastName = sectionName.Split('.').Last(); + var property = JObject.Parse(json) + .Descendants() + .OfType() + .Where(x => x.Name == lastName && getFullName(x) == sectionName) + .Single(); + + if (ignoreProperties.Length > 0) + { + if (property.Value is JObject value) + { + removeProperties(value); + } + else if (property.Value is JArray array) + { + foreach (var element in array.Values()) + { + removeProperties(element!); + } + } + else + { + throw new InvalidOperationException(); + } + + void removeProperties(JObject value) + { + foreach (var ignoreProperty in ignoreProperties) + { + value.Properties().Where(x => x.Name == ignoreProperty).Single().Remove(); + } + } + } + + return property; + + static string getFullName(JProperty property) + { + string name = property.Name; + while (property.Parent is JObject obj) + { + if (obj.Parent is JProperty parent) + { + name = $"{parent.Name}.{name}"; + property = parent; + } + else if (obj.Parent is JArray { Parent: JProperty arrayParent } array) + { + name = $"[].{name}"; + property = arrayParent; + } + else + { + break; + } + } + + return name; + } + } + + protected JObject GetCompilationOptionsValue(CompilationOptions options) + { + var compilation = CreateCompilation(syntaxTrees: new SyntaxTree[] { }, options: (TCompilationOptions)options); + var property = GetJsonProperty(compilation.GetDeterministicKey(), "compilation.options"); + return (JObject)property.Value; + } + + protected JObject GetCompilationValue(Compilation compilation) + { + var property = GetJsonProperty(compilation.GetDeterministicKey(), "compilation"); + return (JObject)property.Value; + } + + protected JObject GetParseOptionsValue(ParseOptions parseOptions) + { + var syntaxTree = ParseSyntaxTree("", fileName: "test", SourceHashAlgorithm.Sha256, (TParseOptions)parseOptions); + var compilation = CreateCompilation(syntaxTrees: new SyntaxTree[] { syntaxTree }); + var property = GetJsonProperty(compilation.GetDeterministicKey(), "compilation.syntaxTrees"); + var trees = (JArray)property.Value; + var obj = (JObject)trees[0]; + return (JObject)(obj.Property("parseOptions")?.Value!); + } + + protected JArray GetReferenceValues(Compilation compilation) + { + var property = GetJsonProperty(compilation.GetDeterministicKey(), "compilation.references"); + return (JArray)property.Value; + } + + protected JObject GetReferenceValue(MetadataReference reference) + { + var expectedMvid = DeterministicKeyBuilder.GetGuidValue(reference.GetModuleVersionId()); + var compilation = CreateCompilation(syntaxTrees: new SyntaxTree[] { }, references: new[] { reference }); + var array = GetReferenceValues(compilation); + + foreach (var item in array!.Values()) + { + if (item?.Value("mvid") == expectedMvid) + { + return item; + } + } + + Assert.True(false, $"Could not find reference with MVID {expectedMvid}"); + throw null!; + } + + protected static JArray GetSyntaxTreeValues(Compilation compilation, ImmutableArray> pathMap = default) + { + var property = GetJsonProperty(compilation.GetDeterministicKey(pathMap: pathMap), "compilation.syntaxTrees"); + return (JArray)property.Value; ; + } + + protected static JArray GetAdditionalTextValues(Compilation compilation, ImmutableArray additionalTexts, ImmutableArray> pathMap = default) + { + var property = GetJsonProperty(compilation.GetDeterministicKey(additionalTexts: additionalTexts, pathMap: pathMap), "additionalTexts"); + return (JArray)property.Value; + } + + protected static JArray GetAnalyzerValues(Compilation compilation, params DiagnosticAnalyzer[] analyzers) + { + var property = GetJsonProperty(compilation.GetDeterministicKey(analyzers: analyzers.ToImmutableArray()), "analyzers"); + return (JArray)property.Value; + } + + protected static JArray GetGeneratorValues(Compilation compilation, params ISourceGenerator[] generators) + { + var property = GetJsonProperty(compilation.GetDeterministicKey(generators: generators.ToImmutableArray()), "generators"); + return (JArray)property.Value; + } + + private protected JObject GetEmitOptionsValue( + EmitOptions emitOptions, + ImmutableArray> pathMap = default, + DeterministicKeyOptions options = default) + { + var compilation = CreateCompilation(new SyntaxTree[] { }); + var key = compilation.GetDeterministicKey( + emitOptions: emitOptions, + pathMap: pathMap, + options: options); + var property = GetJsonProperty(key, "emitOptions"); + return (JObject)property.Value; + } + + protected static string GetChecksum(SourceText text) + { + var checksum = text.GetChecksum(); + var builder = PooledStringBuilder.GetInstance(); + DeterministicKeyBuilder.EncodeByteArrayValue(checksum.AsSpan(), builder); + return builder.ToStringAndFree(); + } + + protected abstract SyntaxTree ParseSyntaxTree(string content, string fileName, SourceHashAlgorithm hashAlgorithm, TParseOptions? parseOptions = null); + + protected abstract TCompilation CreateCompilation( + SyntaxTree[] syntaxTrees, + MetadataReference[]? references = null, + TCompilationOptions? options = null); + + protected abstract TCompilationOptions GetCompilationOptions(); + + protected abstract TParseOptions GetParseOptions(); + + private protected abstract DeterministicKeyBuilder GetDeterministicKeyBuilder(); + + [Theory] + [InlineData(@"hello world")] + [InlineData(@"just need some text here")] + [InlineData(@"yet another case")] + public void SyntaxTreeContent(string content) + { + foreach (var hashAlgorithm in HashAlgorithms) + { + var syntaxTree = ParseSyntaxTree(content, fileName: "file.cs", hashAlgorithm); + var contentChecksum = GetChecksum(syntaxTree.GetText()); + var compilation = CreateCompilation(new[] { syntaxTree }); + var key = compilation.GetDeterministicKey(); + var expected = @$" +""syntaxTrees"": [ + {{ + ""fileName"": ""file.cs"", + ""text"": {{ + ""checksum"": ""{contentChecksum}"", + ""checksumAlgorithm"": ""{hashAlgorithm}"", + ""encodingName"": ""Unicode (UTF-8)"" + }} + }} +]"; + AssertJsonSection(expected, key, "compilation.syntaxTrees", "parseOptions"); + } + } + + [Theory] + [CombinatorialData] + public void CompilationOptionsCombination( + OutputKind outputKind, + bool delaySign, + bool publicSign, + bool deterministic) + { + var options = GetCompilationOptions() + .WithOutputKind(outputKind) + .WithDelaySign(delaySign) + .WithPublicSign(publicSign) + .WithDeterministic(deterministic); + + var obj = GetCompilationOptionsValue(options); + Assert.Equal(outputKind.ToString(), obj.Value("outputKind")); + Assert.Equal(publicSign, obj.Value("publicSign")); + Assert.Equal(delaySign, obj.Value("delaySign")); + Assert.Equal(deterministic, obj.Value("deterministic")); + } + + /// + /// Makes sure that local time is not encoded for deterministic builds. Otherwise deterministic + /// builds would not have deterministic keys + /// + [Fact] + public void CompilationOptionsDeterministic() + { + var obj = getValue(deterministic: true); + Assert.Null(obj.Value("localtime")); + + obj = getValue(deterministic: false); + Assert.NotNull(obj.Value("localtime")); + + JObject getValue(bool deterministic) + { + var options = GetCompilationOptions() + .WithDeterministic(deterministic); + + return GetCompilationOptionsValue(options); + } + } + + /// + /// Disabling determinism should mean all calls to GetDeteriministicKey return different values. + /// + [Fact] + public void CompilationOptionsDeterministicOff() + { + var options = GetCompilationOptions(); + var compilation = CreateCompilation(syntaxTrees: new SyntaxTree[] { }, options: options); + var key = compilation.GetDeterministicKey(); + + Assert.Equal(key, compilation.GetDeterministicKey()); + + options = (TCompilationOptions)options.WithDeterministic(false); + compilation = (TCompilation)compilation.WithOptions(options); + key = compilation.GetDeterministicKey(); + Assert.NotEqual(key, compilation.GetDeterministicKey()); + } + + /// + /// Verify that options which don't impact determinism are excluded from the key + /// + [Theory] + [CombinatorialData] + public void CompilationOptionsExcluded(bool concurrentBuild, MetadataImportOptions metaImportOptions) + { + var options = GetCompilationOptions(); + var other = options + .WithConcurrentBuild(concurrentBuild) + .WithMetadataImportOptions(metaImportOptions); + + var expected = GetCompilationOptionsValue(options); + var actual = GetCompilationOptionsValue(other); + Assert.Equal(expected.ToString(), actual.ToString()); + } + + [Fact] + public void CompilationOptionsSpecificDiagnosticOptions() + { + assert(@"[]"); + assert(@" +[ + { + ""CA109"": ""Error"" + } +]", ("CA109", ReportDiagnostic.Error)); + + assert(@" +[ + { + ""CA109"": ""Error"" + }, + { + ""CA200"": ""Warn"" + } +]", ("CA109", ReportDiagnostic.Error), ("CA200", ReportDiagnostic.Warn)); + + void assert(string expected, params (string Diagnostic, ReportDiagnostic ReportDiagnostic)[] values) + { + var map = values.ToImmutableDictionary( + x => x.Diagnostic, + x => x.ReportDiagnostic); + + var options = GetCompilationOptions() + .WithSpecificDiagnosticOptions(map); + var value = GetCompilationOptionsValue(options); + var actual = value["specificDiagnosticOptions"]?.ToString(Formatting.Indented); + AssertJsonCore(expected, actual); + } + } + + [Theory] + [CombinatorialData] + public void ParseOptionsCombination( + SourceCodeKind sourceCodeKind, + DocumentationMode documentationMode) + { + var parseOptions = GetParseOptions() + .WithKind(sourceCodeKind) + .WithDocumentationMode(documentationMode); + +#pragma warning disable 618 + if (sourceCodeKind == SourceCodeKind.Interactive) + { + sourceCodeKind = SourceCodeKind.Script; + } +#pragma warning restore 618 + + var obj = GetParseOptionsValue(parseOptions); + Assert.Equal(sourceCodeKind.ToString(), obj.Value("kind")); + Assert.Equal(documentationMode.ToString(), obj.Value("documentationMode")); + Assert.Empty(obj.Value("features")!.Properties()); + } + + [Fact] + public void ParseOptionsFeatures() + { + var parseOptions = GetParseOptions(); + + assert("{}"); + assert(@" +{ + ""key"": ""value"" +}", ("key", "value")); + + assert(@" +{ + ""k1"": ""v1"", + ""k2"": ""v2"" +}", ("k1", "v1"), ("k2", "v2")); + + // Same case but reverse the order the keys are added. That should not change the key + assert(@" +{ + ""k1"": ""v1"", + ""k2"": ""v2"" +}", ("k2", "v2"), ("k1", "v1")); + + // Make sure that the keys are escaped properly + assert(@" +{ + ""\\\""strange"": ""value"" +}", (@"\""strange", "value")); + + void assert(string? expected, params (string Key, string Value)[] features) + { + var parseOptions = GetParseOptions() + .WithFeatures(features.Select(x => new KeyValuePair(x.Key, x.Value))); + + var obj = GetParseOptionsValue(parseOptions); + var value = obj.Value("features"); + AssertJsonCore(expected, value?.ToString(Formatting.Indented)); + } + } + + [Fact] + public void EmitOptionsDefault() + { + var obj = GetEmitOptionsValue(EmitOptions); + AssertJson(@" +{ + ""emitMetadataOnly"": false, + ""tolerateErrors"": false, + ""includePrivateMembers"": true, + ""instrumentationKinds"": [ + ], + ""subsystemVersion"": { + ""major"": 0, + ""minor"": 0 + }, + ""fileAlignment"": 0, + ""highEntropyVirtualAddressSpace"": false, + ""baseAddress"": ""0"", + ""debugInformationFormat"": ""Pdb"", + ""outputNameOverride"": null, + ""pdbFilePath"": null, + ""pdbChecksumAlgorithm"": ""SHA256"", + ""runtimeMetadataVersion"": null, + ""defaultSourceFileEncoding"": null, + ""fallbackSourceFileEncoding"": null +} +", obj.ToString(Formatting.Indented)); + } + + [Theory] + [CombinatorialData] + public void EmitOptionsCombo( + DebugInformationFormat debugInformationFormat, + InstrumentationKind kind) + { + var emitOptions = EmitOptions + .Default + .WithDebugInformationFormat(debugInformationFormat) + .WithInstrumentationKinds(ImmutableArray.Create(kind)); + + var obj = GetEmitOptionsValue(emitOptions); + AssertJson(@$" +{{ + ""emitMetadataOnly"": false, + ""tolerateErrors"": false, + ""includePrivateMembers"": true, + ""instrumentationKinds"": [ + ""{kind}"", + ], + ""subsystemVersion"": {{ + ""major"": 0, + ""minor"": 0 + }}, + ""fileAlignment"": 0, + ""highEntropyVirtualAddressSpace"": false, + ""baseAddress"": ""0"", + ""debugInformationFormat"": ""{debugInformationFormat}"", + ""outputNameOverride"": null, + ""pdbFilePath"": null, + ""pdbChecksumAlgorithm"": ""SHA256"", + ""runtimeMetadataVersion"": null, + ""defaultSourceFileEncoding"": null, + ""fallbackSourceFileEncoding"": null +}} +", obj.ToString(Formatting.Indented)); + } + + [Theory] + [InlineData(1, 2)] + [InlineData(3, 4)] + public void EmitOptionsSubsystemVersion(int major, int minor) + { + var emitOptions = EmitOptions.WithSubsystemVersion(SubsystemVersion.Create(major, minor)); + var obj = GetEmitOptionsValue(emitOptions); + var expected = @$" +""subsystemVersion"": {{ + ""major"": {major}, + ""minor"": {minor} +}}"; + AssertJsonSection(expected, obj.ToString(Formatting.Indented), "subsystemVersion"); + } + + [Fact] + public void EmitOptionsPdbFilePathRespectsOptions() + { + var path = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? @"c:\temp\util.pdb" + : "/temp/util.pdb"; + var emitOptions = EmitOptions.WithPdbFilePath(path); + var obj = GetEmitOptionsValue(emitOptions, options: DeterministicKeyOptions.IgnorePaths); + Assert.Equal(@"util.pdb", obj.Value("pdbFilePath")); + } + + [Theory] + [InlineData(@"c:\src\util.pdb", null, null)] + [InlineData(@"d:\src\util.pdb", @"d:\", @"c:\")] + [InlineData(@"d:\long\src\util.pdb", @"d:\long\", @"c:\")] + public void EmitOptionsPdbFilePathRespectsPathMap(string filePath, string? pathMapFrom, string? pathMapTo) + { + var pathMap = (pathMapFrom, pathMapTo) switch + { + (null, null) => ImmutableArray>.Empty, + (string, string) => ImmutableArray.Create(KeyValuePairUtil.Create(pathMapFrom, pathMapTo)), + _ => throw new InvalidOperationException(), + }; + var emitOptions = EmitOptions.WithPdbFilePath(filePath); + var obj = GetEmitOptionsValue(emitOptions, pathMap); + Assert.Equal(@"c:\src\util.pdb", obj.Value("pdbFilePath")); + } + + [Fact] + public void MetadataReferenceMscorlib() + { + var mscorlib = NetCoreApp.mscorlib; + var obj = GetReferenceValue(mscorlib); + + var mvid = DeterministicKeyBuilder.GetGuidValue(mscorlib.GetModuleVersionId()); + var expected = $@" +{{ + ""name"": ""mscorlib"", + ""version"": {{ + ""major"": 4, + ""minor"": 0, + ""build"": 0, + ""revision"": 0 + }}, + ""publicKey"": ""0000000040000000"", + ""mvid"": ""{mvid}"", + ""secondaryModules"": [], + ""properties"": {{ + ""kind"": ""Assembly"", + ""embedInteropTypes"": false, + ""aliases"": [] + }} +}} +"; + + AssertJsonCore(expected, obj.ToString(Formatting.Indented)); + } + + [Fact] + public void MetadataReferenceMscorlibWithAlias() + { + var mscorlib = NetCoreApp.mscorlib.WithAliases(new[] { "alias1", "alias2" }); + var obj = GetReferenceValue(mscorlib); + + var mvid = DeterministicKeyBuilder.GetGuidValue(mscorlib.GetModuleVersionId()); + var expected = $@" +{{ + ""name"": ""mscorlib"", + ""version"": {{ + ""major"": 4, + ""minor"": 0, + ""build"": 0, + ""revision"": 0 + }}, + ""publicKey"": ""0000000040000000"", + ""mvid"": ""{mvid}"", + ""secondaryModules"": [], + ""properties"": {{ + ""kind"": ""Assembly"", + ""embedInteropTypes"": false, + ""aliases"": [ + ""alias1"", + ""alias2"" + ] + }} +}} +"; + + AssertJsonCore(expected, obj.ToString(Formatting.Indented)); + } + + [Theory] + [CombinatorialData] + public void MetadataReferenceMscorlibEmbedInteropTypes(bool embedInteropTypes) + { + var mscorlib = NetCoreApp.mscorlib.WithEmbedInteropTypes(embedInteropTypes); + var obj = GetReferenceValue(mscorlib); + + var mvid = DeterministicKeyBuilder.GetGuidValue(mscorlib.GetModuleVersionId()); + var expected = $@" +{{ + ""name"": ""mscorlib"", + ""version"": {{ + ""major"": 4, + ""minor"": 0, + ""build"": 0, + ""revision"": 0 + }}, + ""publicKey"": ""0000000040000000"", + ""mvid"": ""{mvid}"", + ""secondaryModules"": [], + ""properties"": {{ + ""kind"": ""Assembly"", + ""embedInteropTypes"": {embedInteropTypes.ToString().ToLowerInvariant()}, + ""aliases"": [] + }} +}} +"; + + AssertJsonCore(expected, obj.ToString(Formatting.Indented)); + } + + [Fact] + public void MetadataReferenceMultiModule() + { + var reference = TestReferences.SymbolsTests.MultiModule.Assembly; + var obj = GetReferenceValue(reference); + + var expected = @" +{ + ""name"": ""MultiModule"", + ""version"": { + ""major"": 0, + ""minor"": 0, + ""build"": 0, + ""revision"": 0 + }, + ""publicKey"": """", + ""mvid"": ""0f07ef6c-4b63-421d-870e-1358db815764"", + ""secondaryModules"": [ + { + ""name"": ""mod2.netmodule"", + ""mvid"": ""82f316ce-66f1-45b6-a2c7-b4476bda03fd"" + }, + { + ""name"": ""mod3.netmodule"", + ""mvid"": ""ff9f3a02-95e7-44b2-a278-e9149fa82ee4"" + } + ], + ""properties"": { + ""kind"": ""Assembly"", + ""embedInteropTypes"": false, + ""aliases"": [] + } +}"; + + AssertJsonCore(expected, obj.ToString(Formatting.Indented)); + } + + + [Theory] + [InlineData(@"c:\src\data.txt", null, null)] + [InlineData(@"d:\src\data.txt", @"d:\", @"c:\")] + [InlineData(@"d:\long\src\data.txt", @"d:\long\", @"c:\")] + public void PathMapAdditionalFiles(string filePath, string? pathMapFrom, string? pathMapTo) + { + var pathMap = (pathMapFrom, pathMapTo) switch + { + (null, null) => ImmutableArray>.Empty, + (string, string) => ImmutableArray.Create(KeyValuePairUtil.Create(pathMapFrom, pathMapTo)), + _ => throw new InvalidOperationException(), + }; + + var additionalText = new InMemoryAdditionalText(filePath, "hello world"); + var array = GetAdditionalTextValues( + CreateCompilation(new SyntaxTree[] { }), + ImmutableArray.Create(additionalText), + pathMap); + + var expected = @" +[ + { + ""fileName"": ""c:\\src\\data.txt"", + ""text"": { + ""checksum"": ""8f8ceeeb5e1b799fe3c7dd9f059bf8852c57cb"", + ""checksumAlgorithm"": ""Sha1"", + ""encodingName"": ""Unicode (UTF-8)"" + } + } +] +"; + + AssertJsonCore(expected, array.ToString(Formatting.Indented)); + } + + [Fact] + public void AdditionalTextError() + { + var additionalText = new TestAdditionalText(path: @"test.txt", text: null); + var array = GetAdditionalTextValues( + CreateCompilation(new SyntaxTree[] { }), + ImmutableArray.Create(additionalText)); + + var expected = @" +[ + { + ""fileName"": ""test.txt"", + ""text"": null + } +] +"; + + AssertJsonCore(expected, array.ToString(Formatting.Indented)); + } + + [Fact] + public void Analyzers() + { + var array = GetAnalyzerValues( + CreateCompilation(Array.Empty()), + new Analyzer(), + new Analyzer2()); + + var assembly = typeof(Analyzer).Assembly; + var expected = @$" +[ + {{ + ""fullName"": ""{typeof(Analyzer).FullName}"", + ""assemblyName"": ""{assembly.FullName}"", + ""mvid"": ""{DeterministicKeyBuilder.GetGuidValue(assembly.ManifestModule.ModuleVersionId)}"" + }}, + {{ + ""fullName"": ""{typeof(Analyzer2).FullName}"", + ""assemblyName"": ""{assembly.FullName}"", + ""mvid"": ""{DeterministicKeyBuilder.GetGuidValue(assembly.ManifestModule.ModuleVersionId)}"" + }} +] +"; + AssertJsonCore(expected, array.ToString(Formatting.Indented)); + } + + [Fact] + public void Generators() + { + var array = GetGeneratorValues( + CreateCompilation(Array.Empty()), + new Generator(), + new Generator2()); + + var assembly = typeof(Generator).Assembly; + var expected = @$" +[ + {{ + ""fullName"": ""{typeof(Generator).FullName}"", + ""assemblyName"": ""{assembly.FullName}"", + ""mvid"": ""{DeterministicKeyBuilder.GetGuidValue(assembly.ManifestModule.ModuleVersionId)}"" + }}, + {{ + ""fullName"": ""{typeof(Generator2).FullName}"", + ""assemblyName"": ""{assembly.FullName}"", + ""mvid"": ""{DeterministicKeyBuilder.GetGuidValue(assembly.ManifestModule.ModuleVersionId)}"" + }} +] +"; + AssertJsonCore(expected, array.ToString(Formatting.Indented)); + } + } +} diff --git a/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj b/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj index f59d28a39b178..c01139fd1e963 100644 --- a/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj +++ b/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj @@ -17,9 +17,10 @@ + - + diff --git a/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.CSharpRebuildCompiler.cs b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.CSharpRebuildCompiler.cs deleted file mode 100644 index 6a5c96f9678be..0000000000000 --- a/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.CSharpRebuildCompiler.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.CSharp; - -namespace Microsoft.CodeAnalysis.Rebuild.UnitTests -{ - public partial class RebuildCommandLineTests - { - private sealed class CSharpRebuildCompiler : CSharpCompiler - { - internal CSharpRebuildCompiler(string[] args) - : base(CSharpCommandLineParser.Default, responseFile: null, args, StandardBuildPaths, additionalReferenceDirectories: null, new DefaultAnalyzerAssemblyLoader()) - { - } - } - } -} diff --git a/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.VisualBasicRebuildCompiler.cs b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.VisualBasicRebuildCompiler.cs deleted file mode 100644 index 8cf958b08aeb1..0000000000000 --- a/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.VisualBasicRebuildCompiler.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.VisualBasic; - -namespace Microsoft.CodeAnalysis.Rebuild.UnitTests -{ - public partial class RebuildCommandLineTests - { - private sealed class VisualBasicRebuildCompiler : VisualBasicCompiler - { - internal VisualBasicRebuildCompiler(string[] args) - : base(VisualBasicCommandLineParser.Default, responseFile: null, args, StandardBuildPaths, additionalReferenceDirectories: null, new DefaultAnalyzerAssemblyLoader()) - { - } - } - } -} diff --git a/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.cs b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.cs index 9c914425c148f..fa0dee9b65980 100644 --- a/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.cs +++ b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.cs @@ -21,13 +21,9 @@ public sealed partial class RebuildCommandLineTests : CSharpTestBase { private record CommandInfo(string CommandLine, string PeFileName, string? PdbFileName, string? CommandLineSuffix = null); - internal static string RootDirectory => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"q:\" : "/"; - internal static string ClientDirectory => Path.Combine(RootDirectory, "compiler"); - internal static string WorkingDirectory => Path.Combine(RootDirectory, "rebuild"); - internal static string SdkDirectory => Path.Combine(RootDirectory, "sdk"); - internal static string OutputDirectory => Path.Combine(RootDirectory, "output"); - - internal static BuildPaths StandardBuildPaths => new BuildPaths(ClientDirectory, WorkingDirectory, SdkDirectory, tempDir: null); + internal static BuildPaths BuildPaths { get; } = TestableCompiler.StandardBuildPaths; + internal static string RootDirectory { get; } = TestableCompiler.RootDirectory; + internal static string OutputDirectory { get; } = Path.Combine(TestableCompiler.RootDirectory, "output"); public ITestOutputHelper TestOutputHelper { get; } public Dictionary FilePathToStreamMap { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -39,12 +35,12 @@ public RebuildCommandLineTests(ITestOutputHelper testOutputHelper) private void AddSourceFile(string filePath, string content) { - FilePathToStreamMap.Add(Path.Combine(WorkingDirectory, filePath), new TestableFile(content)); + FilePathToStreamMap.Add(Path.Combine(BuildPaths.WorkingDirectory, filePath), new TestableFile(content)); } private void AddReference(string filePath, byte[] imageBytes) { - FilePathToStreamMap.Add(Path.Combine(SdkDirectory, filePath), new TestableFile(imageBytes)); + FilePathToStreamMap.Add(Path.Combine(BuildPaths.SdkDirectory!, filePath), new TestableFile(imageBytes)); } private void AddOutputFile(ref string? filePath) @@ -97,15 +93,14 @@ private static IEnumerable PermutateExeKinds(CommandInfo commandInf private void VerifyRoundTrip(CommonCompiler commonCompiler, string peFilePath, string? pdbFilePath = null, CancellationToken cancellationToken = default) { Assert.True(commonCompiler.Arguments.CompilationOptions.Deterministic); - using var writer = new StringWriter(); - commonCompiler.FileSystem = TestableFileSystem.CreateForMap(FilePathToStreamMap); - var result = commonCompiler.Run(writer, cancellationToken); - TestOutputHelper.WriteLine(writer.ToString()); + var (result, output) = commonCompiler.Run(cancellationToken); + TestOutputHelper.WriteLine(output); Assert.Equal(0, result); var peStream = FilePathToStreamMap[peFilePath].GetStream(); var pdbStream = pdbFilePath is object ? FilePathToStreamMap[pdbFilePath].GetStream() : null; + using var writer = new StringWriter(); var compilation = commonCompiler.CreateCompilation( writer, touchedFilesLogger: null, @@ -344,11 +339,6 @@ public void CSharp(string commandLine, string peFilePath, string? pdbFilePath, s var args = new List(commandLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)); args.Add("/nostdlib"); args.Add("/deterministic"); - foreach (var referenceInfo in NetCoreApp.AllReferenceInfos) - { - AddReference(referenceInfo.FileName, referenceInfo.ImageBytes); - args.Add($"/r:{referenceInfo.FileName}"); - } AddOutputFile(ref peFilePath!); args.Add($"/out:{peFilePath}"); @@ -364,8 +354,11 @@ public void CSharp(string commandLine, string peFilePath, string? pdbFilePath, s } TestOutputHelper.WriteLine($"Final Line: {string.Join(" ", args)}"); - var compiler = new CSharpRebuildCompiler(args.ToArray()); - VerifyRoundTrip(compiler, peFilePath, pdbFilePath); + var compiler = TestableCompiler.CreateCSharpNetCoreApp( + TestableFileSystem.CreateForMap(FilePathToStreamMap), + BuildPaths, + args); + VerifyRoundTrip(compiler.Compiler, peFilePath, pdbFilePath); } private void AddVisualBasicSourceFiles() @@ -511,17 +504,6 @@ public void VisualBasic(string commandLine, string peFilePath, string? pdbFilePa var args = new List(commandLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)); args.Add("/nostdlib"); args.Add("/deterministic"); - foreach (var referenceInfo in NetCoreApp.AllReferenceInfos) - { - AddReference(referenceInfo.FileName, referenceInfo.ImageBytes); - - // The command line needs to make a decision about how to embed the VB runtime - if (referenceInfo.FileName != "Microsoft.VisualBasic.dll") - { - args.Add($"/r:{referenceInfo.FileName}"); - } - } - AddOutputFile(ref peFilePath!); args.Add($"/out:{peFilePath}"); AddOutputFile(ref pdbFilePath); @@ -531,8 +513,12 @@ public void VisualBasic(string commandLine, string peFilePath, string? pdbFilePa } TestOutputHelper.WriteLine($"Final Line: {string.Join(" ", args)}"); - var compiler = new VisualBasicRebuildCompiler(args.ToArray()); - VerifyRoundTrip(compiler, peFilePath, pdbFilePath); + var compiler = TestableCompiler.CreateBasicNetCoreApp( + TestableFileSystem.CreateForMap(FilePathToStreamMap), + BuildPaths, + BasicRuntimeOption.Manual, + args); + VerifyRoundTrip(compiler.Compiler, peFilePath, pdbFilePath); } } } diff --git a/src/Compilers/Test/Core/Assert/AssertEx.cs b/src/Compilers/Test/Core/Assert/AssertEx.cs index 10d6b8dadda69..7cdcdded82c88 100644 --- a/src/Compilers/Test/Core/Assert/AssertEx.cs +++ b/src/Compilers/Test/Core/Assert/AssertEx.cs @@ -234,6 +234,22 @@ public static void Equal( Assert.True(false, GetAssertMessage(expected, actual, comparer, message, itemInspector, itemSeparator, expectedValueSourcePath, expectedValueSourceLine)); } + public static void Equal( + ReadOnlySpan expected, + ReadOnlySpan actual, + IEqualityComparer comparer = null, + string message = null, + string itemSeparator = null, + Func itemInspector = null, + string expectedValueSourcePath = null, + int expectedValueSourceLine = 0) + { + if (SequenceEqual(expected, actual, comparer)) + return; + + Assert.True(false, GetAssertMessage(expected, actual, comparer, message, itemInspector, itemSeparator, expectedValueSourcePath, expectedValueSourceLine)); + } + /// /// Asserts that two strings are equal, and prints a diff between the two if they are not. /// @@ -336,6 +352,22 @@ private static bool SequenceEqual(IEnumerable expected, IEnumerable act return true; } + private static bool SequenceEqual(ReadOnlySpan expected, ReadOnlySpan actual, IEqualityComparer comparer = null) + { + if (expected.Length != actual.Length) + return false; + + for (int i = 0; i < expected.Length; i++) + { + if (!(comparer is not null ? comparer.Equals(expected[i], actual[i]) : AssertEqualityComparer.Equals(expected[i], actual[i]))) + { + return false; + } + } + + return true; + } + public static void SetEqual(IEnumerable expected, IEnumerable actual, IEqualityComparer comparer = null, string message = null, string itemSeparator = "\r\n", Func itemInspector = null) { var indexes = new Dictionary(comparer); @@ -673,6 +705,86 @@ public static string GetAssertMessage( return message.ToString(); } + public static string GetAssertMessage( + ReadOnlySpan expected, + ReadOnlySpan actual, + IEqualityComparer comparer = null, + string prefix = null, + Func itemInspector = null, + string itemSeparator = null, + string expectedValueSourcePath = null, + int expectedValueSourceLine = 0) + { + if (itemInspector == null) + { + if (typeof(T) == typeof(byte)) + { + itemInspector = b => $"0x{b:X2}"; + } + else + { + itemInspector = new Func(obj => (obj != null) ? obj.ToString() : ""); + } + } + + if (itemSeparator == null) + { + if (typeof(T) == typeof(byte)) + { + itemSeparator = ", "; + } + else + { + itemSeparator = "," + Environment.NewLine; + } + } + + const int maxDisplayedExpectedEntries = 10; + var expectedString = join(itemSeparator, expected[..Math.Min(expected.Length, maxDisplayedExpectedEntries)], itemInspector); + var actualString = join(itemSeparator, actual, itemInspector); + + var message = new StringBuilder(); + + if (!string.IsNullOrEmpty(prefix)) + { + message.AppendLine(prefix); + message.AppendLine(); + } + + message.AppendLine("Expected:"); + message.AppendLine(expectedString); + if (expected.Length > maxDisplayedExpectedEntries) + { + message.AppendLine("... truncated ..."); + } + + message.AppendLine("Actual:"); + message.AppendLine(actualString); + message.AppendLine("Differences:"); + message.AppendLine(DiffUtil.DiffReport(expected.ToArray(), actual.ToArray(), itemSeparator, comparer, itemInspector)); + + if (TryGenerateExpectedSourceFileAndGetDiffLink(actualString, expected.Length, expectedValueSourcePath, expectedValueSourceLine, out var link)) + { + message.AppendLine(link); + } + + return message.ToString(); + + static string join(string itemSeparator, ReadOnlySpan items, Func itemInspector) + { + var result = new StringBuilder(); + var iter = items.GetEnumerator(); + + if (iter.MoveNext()) + result.Append(itemInspector(iter.Current)); + + while (iter.MoveNext()) + result.Append($"{itemSeparator}{itemInspector(iter.Current)}"); + + return result.ToString(); + } + } + internal static bool TryGenerateExpectedSourceFileAndGetDiffLink(string actualString, int expectedLineCount, string expectedValueSourcePath, int expectedValueSourceLine, out string link) { // add a link to a .cmd file that opens a diff tool: @@ -815,10 +927,12 @@ public static void Multiple(bool includeStackTrace, params Action[] assertions) if (exceptions is null) return; - var stringBuilder = new StringBuilder($"{exceptions.Count} out of {assertions.Length} assertions failed."); + var stringBuilder = new StringBuilder() + .AppendLine($"{exceptions.Count} out of {assertions.Length} assertions failed.") + .AppendLine(); foreach (var (index, ex) in exceptions) { - var stack = ex.StackTrace.Split(new[] { "\r\n" }, StringSplitOptions.None); + var stack = ex.StackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None); stringBuilder .AppendLine($"Assertion failed at index {index}:") .AppendLine(stack[^2]) // Prints the failing line in the original test case. diff --git a/src/Compilers/Test/Core/CommonCompilerExtensions.cs b/src/Compilers/Test/Core/CommonCompilerExtensions.cs new file mode 100644 index 0000000000000..fcbe090055fad --- /dev/null +++ b/src/Compilers/Test/Core/CommonCompilerExtensions.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; + +namespace Roslyn.Test.Utilities +{ + internal static class CommonCompilerExtensions + { + internal static (int Result, string Output) Run(this CommonCompiler compiler, CancellationToken cancellationToken = default) + { + using var writer = new StringWriter(); + var result = compiler.Run(writer, cancellationToken); + return (result, writer.ToString()); + } + } +} diff --git a/src/Compilers/Test/Core/CommonTestBase.cs b/src/Compilers/Test/Core/CommonTestBase.cs index e92f2e5628e72..6ebb554eb620a 100644 --- a/src/Compilers/Test/Core/CommonTestBase.cs +++ b/src/Compilers/Test/Core/CommonTestBase.cs @@ -23,11 +23,15 @@ namespace Microsoft.CodeAnalysis.Test.Utilities { + [Flags] public enum Verification { - Passes = 0, - Fails, - Skipped + Skipped = 0, + Passes = 1 << 1, + + FailsPEVerify = 1 << 2, + FailsILVerify = 1 << 3, + Fails = FailsPEVerify | FailsILVerify, } /// @@ -46,6 +50,7 @@ internal CompilationVerifier CompileAndVerifyCommon( Action symbolValidator = null, SignatureDescription[] expectedSignatures = null, string expectedOutput = null, + bool trimOutput = true, int? expectedReturnCode = null, string[] args = null, EmitOptions emitOptions = null, @@ -70,6 +75,7 @@ internal CompilationVerifier CompileAndVerifyCommon( manifestResources, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args ?? Array.Empty(), assemblyValidator, @@ -142,6 +148,7 @@ internal CompilationVerifier Emit( IEnumerable manifestResources, SignatureDescription[] expectedSignatures, string expectedOutput, + bool trimOutput, int? expectedReturnCode, string[] args, Action assemblyValidator, @@ -151,12 +158,12 @@ internal CompilationVerifier Emit( { var verifier = new CompilationVerifier(compilation, VisualizeRealIL, dependencies); - verifier.Emit(expectedOutput, expectedReturnCode, args, manifestResources, emitOptions, verify, expectedSignatures); + verifier.Emit(expectedOutput, trimOutput, expectedReturnCode, args, manifestResources, emitOptions, verify, expectedSignatures); if (assemblyValidator != null || symbolValidator != null) { // We're dual-purposing emitters here. In this context, it - // tells the validator the version of Emit that is calling it. + // tells the validator the version of Emit that is calling it. RunValidators(verifier, assemblyValidator, symbolValidator); } @@ -549,7 +556,7 @@ private static Dictionary GetParentOperationsMap(Semanti private static void CollectParentOperations(IOperation operation, Dictionary map) { // walk down to collect all parent operation map for this tree - foreach (var child in operation.Children.WhereNotNull()) + foreach (var child in operation.ChildOperations) { map.Add(child, operation); @@ -618,7 +625,7 @@ private static void VerifyOperationTreeContracts(IOperation root) // all operations from spine should belong to the operation tree set VerifyOperationTreeSpine(semanticModel, set, child.Syntax); - // operation tree's node must be part of root of semantic model which is + // operation tree's node must be part of root of semantic model which is // owner of operation's lifetime Assert.True(semanticModel.Root.FullSpan.Contains(child.Syntax.FullSpan)); } diff --git a/src/Compilers/Test/Core/Compilation/IRuntimeEnvironment.cs b/src/Compilers/Test/Core/Compilation/IRuntimeEnvironment.cs index c17c634d67adb..062c07931cd62 100644 --- a/src/Compilers/Test/Core/Compilation/IRuntimeEnvironment.cs +++ b/src/Compilers/Test/Core/Compilation/IRuntimeEnvironment.cs @@ -9,7 +9,6 @@ using System.Collections.Immutable; using System.IO; using System.Linq; -using System.Reflection; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Runtime.InteropServices; @@ -91,7 +90,7 @@ private static IEnumerable EnumerateModules(Metadata metadata) /// /// Emit all of the references which are not directly or indirectly a value. /// - internal static void EmitReferences(Compilation compilation, HashSet fullNameSet, List dependencies, DiagnosticBag diagnostics) + internal static void EmitReferences(Compilation compilation, HashSet fullNameSet, List dependencies, DiagnosticBag diagnostics, AssemblyIdentity corLibIdentity) { // NOTE: specifically don't need to consider previous submissions since they will always be compilations. foreach (var metadataReference in compilation.References) @@ -115,6 +114,7 @@ internal static void EmitReferences(Compilation compilation, HashSet ful continue; } + var isCorLib = isManifestModule && corLibIdentity == identity; foreach (var module in EnumerateModules(metadata)) { ImmutableArray bytes = module.Module.PEReaderOpt.GetEntireImage().GetContent(); @@ -126,14 +126,16 @@ internal static void EmitReferences(Compilation compilation, HashSet ful OutputKind.DynamicallyLinkedLibrary, bytes, pdb: default(ImmutableArray), - inMemoryModule: true); + inMemoryModule: true, + isCorLib); } else { moduleData = new ModuleData(module.Name, bytes, pdb: default(ImmutableArray), - inMemoryModule: true); + inMemoryModule: true, + isCorLib: false); } dependencies.Add(moduleData); @@ -194,9 +196,10 @@ private static List FindDirectReferencedCompilations(Compilation co List dependencies, DiagnosticBag diagnostics, CompilationTestData testData, - EmitOptions emitOptions - ) + EmitOptions emitOptions) { + var corLibIdentity = compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly.Identity; + // A Compilation can appear multiple times in a dependency graph as both a Compilation and as a MetadataReference // value. Iterate the Compilations eagerly so they are always emitted directly and later references can re-use // the value. This gives better, and consistent, diagnostic information. @@ -208,11 +211,13 @@ EmitOptions emitOptions var emitData = EmitCompilationCore(referencedCompilation, null, diagnostics, null, emitOptions); if (emitData.HasValue) { - var moduleData = new ModuleData(referencedCompilation.Assembly.Identity, + var identity = referencedCompilation.Assembly.Identity; + var moduleData = new ModuleData(identity, OutputKind.DynamicallyLinkedLibrary, emitData.Value.Assembly, pdb: default(ImmutableArray), - inMemoryModule: true); + inMemoryModule: true, + isCorLib: corLibIdentity == identity); fullNameSet.Add(moduleData.Id.FullName); dependencies.Add(moduleData); } @@ -221,7 +226,7 @@ EmitOptions emitOptions // Now that the Compilation values have been emitted, emit the non-compilation references foreach (var current in (new[] { compilation }).Concat(referencedCompilations)) { - EmitReferences(current, fullNameSet, dependencies, diagnostics); + EmitReferences(current, fullNameSet, dependencies, diagnostics, corLibIdentity); } return EmitCompilationCore(compilation, manifestResources, diagnostics, testData, emitOptions); @@ -242,6 +247,7 @@ EmitOptions emitOptions var assembly = default(ImmutableArray); var pdbStream = (emitOptions.DebugInformationFormat != DebugInformationFormat.Embedded) ? new MemoryStream() : null; + // Note: don't forget to name the source inputs to get them embedded for debugging var embeddedTexts = compilation.SyntaxTrees .Select(t => (filePath: t.FilePath, text: t.GetText())) .Where(t => t.text.CanBeEmbedded && !string.IsNullOrEmpty(t.filePath)) @@ -386,7 +392,7 @@ public interface IRuntimeEnvironmentFactory public interface IRuntimeEnvironment : IDisposable { void Emit(Compilation mainCompilation, IEnumerable manifestResources, EmitOptions emitOptions, bool usePdbForDebugging = false); - int Execute(string moduleName, string[] args, string expectedOutput); + int Execute(string moduleName, string[] args, string expectedOutput, bool trimOutput = true); ImmutableArray GetMainImage(); ImmutableArray GetMainPdb(); ImmutableArray GetDiagnostics(); diff --git a/src/Compilers/Test/Core/Compilation/MetadataReferenceExtensions.cs b/src/Compilers/Test/Core/Compilation/MetadataReferenceExtensions.cs index cd6e72b7021ed..c4f22e63d1551 100644 --- a/src/Compilers/Test/Core/Compilation/MetadataReferenceExtensions.cs +++ b/src/Compilers/Test/Core/Compilation/MetadataReferenceExtensions.cs @@ -32,7 +32,7 @@ public static ModuleMetadata GetManifestModuleMetadata(this PortableExecutableRe { case AssemblyMetadata assemblyMetadata: { - if (assemblyMetadata.GetModules() is { Length: 1 } modules) + if (assemblyMetadata.GetModules() is { Length: > 0 } modules) { return modules[0]; } diff --git a/src/Compilers/Test/Core/Compilation/OperationTreeVerifier.cs b/src/Compilers/Test/Core/Compilation/OperationTreeVerifier.cs index 52df40063dcf5..416eb5de0b602 100644 --- a/src/Compilers/Test/Core/Compilation/OperationTreeVerifier.cs +++ b/src/Compilers/Test/Core/Compilation/OperationTreeVerifier.cs @@ -387,9 +387,9 @@ internal void VisitRefKindArrayElement(RefKind element) private void VisitChildren(IOperation operation) { - Debug.Assert(operation.Children.All(o => o != null)); + Debug.Assert(operation.ChildOperations.All(o => o != null)); - var children = operation.Children.ToImmutableArray(); + var children = operation.ChildOperations.ToImmutableArray(); if (!children.IsEmpty || operation.Kind != OperationKind.None) { VisitArray(children, "Children", logElementCount: true); diff --git a/src/Compilers/Test/Core/Compilation/TestOperationVisitor.cs b/src/Compilers/Test/Core/Compilation/TestOperationVisitor.cs index b745f614dc66a..c83c1cf512636 100644 --- a/src/Compilers/Test/Core/Compilation/TestOperationVisitor.cs +++ b/src/Compilers/Test/Core/Compilation/TestOperationVisitor.cs @@ -62,11 +62,50 @@ public override void Visit(IOperation operation) var isImplicit = operation.IsImplicit; - foreach (IOperation child in operation.Children) + var count = ((Operation)operation).ChildOperationsCount; + var builder = count == 0 ? null : ArrayBuilder.GetInstance(count); + foreach (IOperation child in operation.ChildOperations) { Assert.NotNull(child); + builder.Add(child); } + Assert.Equal(count, builder?.Count ?? 0); + + if (count > 0) + { + Assert.Same(builder[0], operation.ChildOperations.First()); + Assert.Same(builder[^1], operation.ChildOperations.Last()); + + var forwards = operation.ChildOperations.GetEnumerator(); + Assert.True(forwards.MoveNext()); + var first = forwards.Current; + forwards.Reset(); + Assert.True(forwards.MoveNext()); + Assert.Same(first, forwards.Current); + + var reversed = operation.ChildOperations.Reverse().GetEnumerator(); + Assert.True(reversed.MoveNext()); + var last = reversed.Current; + reversed.Reset(); + Assert.True(reversed.MoveNext()); + Assert.Same(last, reversed.Current); + } + else + { + Assert.Throws(() => operation.ChildOperations.First()); + Assert.Throws(() => operation.ChildOperations.Last()); + } + + foreach (IOperation child in operation.ChildOperations.Reverse()) + { + Assert.NotNull(child); + Assert.Same(child, builder[--count]); + } + + Assert.Equal(0, count); + builder?.Free(); + if (operation.SemanticModel != null) { Assert.Same(operation.SemanticModel, operation.SemanticModel.ContainingModelOrSelf); @@ -80,13 +119,13 @@ public override void VisitBlock(IBlockOperation operation) Assert.Equal(OperationKind.Block, operation.Kind); VisitLocals(operation.Locals); - AssertEx.Equal(operation.Operations, operation.Children); + AssertEx.Equal(operation.Operations, operation.ChildOperations); } public override void VisitVariableDeclarationGroup(IVariableDeclarationGroupOperation operation) { Assert.Equal(OperationKind.VariableDeclarationGroup, operation.Kind); - AssertEx.Equal(operation.Declarations, operation.Children); + AssertEx.Equal(operation.Declarations, operation.ChildOperations); } public override void VisitVariableDeclarator(IVariableDeclaratorOperation operation) @@ -101,7 +140,7 @@ public override void VisitVariableDeclarator(IVariableDeclaratorOperation operat children = children.Concat(new[] { initializer }); } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitVariableDeclaration(IVariableDeclarationOperation operation) @@ -115,7 +154,7 @@ public override void VisitVariableDeclaration(IVariableDeclarationOperation oper children = children.Concat(new[] { initializer }); } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitSwitch(ISwitchOperation operation) @@ -123,14 +162,14 @@ public override void VisitSwitch(ISwitchOperation operation) Assert.Equal(OperationKind.Switch, operation.Kind); VisitLocals(operation.Locals); Assert.NotNull(operation.ExitLabel); - AssertEx.Equal(new[] { operation.Value }.Concat(operation.Cases), operation.Children); + AssertEx.Equal(new[] { operation.Value }.Concat(operation.Cases), operation.ChildOperations); } public override void VisitSwitchCase(ISwitchCaseOperation operation) { Assert.Equal(OperationKind.SwitchCase, operation.Kind); VisitLocals(operation.Locals); - AssertEx.Equal(operation.Clauses.Concat(operation.Body), operation.Children); + AssertEx.Equal(operation.Clauses.Concat(operation.Body), operation.ChildOperations); VerifySubTree(((SwitchCaseOperation)operation).Condition, hasNonNullParent: true); } @@ -175,7 +214,7 @@ public override void VisitSingleValueCaseClause(ISingleValueCaseClauseOperation { VisitCaseClauseOperation(operation); Assert.Equal(CaseKind.SingleValue, operation.CaseKind); - AssertEx.Equal(new[] { operation.Value }, operation.Children); + AssertEx.Equal(new[] { operation.Value }, operation.ChildOperations); } private static void VisitCaseClauseOperation(ICaseClauseOperation operation) @@ -190,14 +229,14 @@ public override void VisitRelationalCaseClause(IRelationalCaseClauseOperation op Assert.Equal(CaseKind.Relational, operation.CaseKind); var relation = operation.Relation; - AssertEx.Equal(new[] { operation.Value }, operation.Children); + AssertEx.Equal(new[] { operation.Value }, operation.ChildOperations); } public override void VisitDefaultCaseClause(IDefaultCaseClauseOperation operation) { VisitCaseClauseOperation(operation); Assert.Equal(CaseKind.Default, operation.CaseKind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } private static void VisitLocals(ImmutableArray locals) @@ -243,7 +282,7 @@ public override void VisitWhileLoop(IWhileLoopOperation operation) } } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitForLoop(IForLoopOperation operation) @@ -263,7 +302,7 @@ public override void VisitForLoop(IForLoopOperation operation) children = children.Concat(new[] { operation.Body }); children = children.Concat(operation.AtLoopBottom); - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitForToLoop(IForToLoopOperation operation) @@ -284,7 +323,7 @@ public override void VisitForToLoop(IForToLoopOperation operation) IEnumerable children; children = new[] { operation.LoopControlVariable, operation.InitialValue, operation.LimitValue, operation.StepValue, operation.Body }; children = children.Concat(operation.NextVariables); - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitForEachLoop(IForEachLoopOperation operation) @@ -293,7 +332,7 @@ public override void VisitForEachLoop(IForEachLoopOperation operation) Assert.Equal(LoopKind.ForEach, operation.LoopKind); IEnumerable children = new[] { operation.Collection, operation.LoopControlVariable, operation.Body }.Concat(operation.NextVariables); - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); ForEachLoopOperationInfo info = ((ForEachLoopOperation)operation).Info; if (info != null) { @@ -330,11 +369,11 @@ public override void VisitLabeled(ILabeledOperation operation) if (operation.Operation == null) { - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } else { - Assert.Same(operation.Operation, operation.Children.Single()); + Assert.Same(operation.Operation, operation.ChildOperations.Single()); } } @@ -354,13 +393,13 @@ public override void VisitBranch(IBranchOperation operation) break; } - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitEmpty(IEmptyOperation operation) { Assert.Equal(OperationKind.Empty, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitReturn(IReturnOperation operation) @@ -369,18 +408,18 @@ public override void VisitReturn(IReturnOperation operation) if (operation.ReturnedValue == null) { Assert.NotEqual(OperationKind.YieldReturn, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } else { - Assert.Same(operation.ReturnedValue, operation.Children.Single()); + Assert.Same(operation.ReturnedValue, operation.ChildOperations.Single()); } } public override void VisitLock(ILockOperation operation) { Assert.Equal(OperationKind.Lock, operation.Kind); - AssertEx.Equal(new[] { operation.LockedValue, operation.Body }, operation.Children); + AssertEx.Equal(new[] { operation.LockedValue, operation.Body }, operation.ChildOperations); } public override void VisitTry(ITryOperation operation) @@ -394,7 +433,7 @@ public override void VisitTry(ITryOperation operation) children = children.Concat(new[] { operation.Finally }); } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitCatchClause(ICatchClauseOperation operation) @@ -415,14 +454,14 @@ public override void VisitCatchClause(ICatchClauseOperation operation) } children = children.Concat(new[] { operation.Handler }); - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitUsing(IUsingOperation operation) { Assert.Equal(OperationKind.Using, operation.Kind); VisitLocals(operation.Locals); - AssertEx.Equal(new[] { operation.Resources, operation.Body }, operation.Children); + AssertEx.Equal(new[] { operation.Resources, operation.Body }, operation.ChildOperations); Assert.NotEqual(OperationKind.VariableDeclaration, operation.Resources.Kind); Assert.NotEqual(OperationKind.VariableDeclarator, operation.Resources.Kind); @@ -442,37 +481,37 @@ internal override void VisitFixed(IFixedOperation operation) { Assert.Equal(OperationKind.None, operation.Kind); VisitLocals(operation.Locals); - AssertEx.Equal(new[] { operation.Variables, operation.Body }, operation.Children); + AssertEx.Equal(new[] { operation.Variables, operation.Body }, operation.ChildOperations); } internal override void VisitAggregateQuery(IAggregateQueryOperation operation) { Assert.Equal(OperationKind.None, operation.Kind); - AssertEx.Equal(new[] { operation.Group, operation.Aggregation }, operation.Children); + AssertEx.Equal(new[] { operation.Group, operation.Aggregation }, operation.ChildOperations); } public override void VisitExpressionStatement(IExpressionStatementOperation operation) { Assert.Equal(OperationKind.ExpressionStatement, operation.Kind); - Assert.Same(operation.Operation, operation.Children.Single()); + Assert.Same(operation.Operation, operation.ChildOperations.Single()); } internal override void VisitWithStatement(IWithStatementOperation operation) { Assert.Equal(OperationKind.None, operation.Kind); - AssertEx.Equal(new[] { operation.Value, operation.Body }, operation.Children); + AssertEx.Equal(new[] { operation.Value, operation.Body }, operation.ChildOperations); } public override void VisitStop(IStopOperation operation) { Assert.Equal(OperationKind.Stop, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitEnd(IEndOperation operation) { Assert.Equal(OperationKind.End, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitInvocation(IInvocationOperation operation) @@ -491,7 +530,7 @@ public override void VisitInvocation(IInvocationOperation operation) children = operation.Arguments; } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); // Make sure that all static member references or invocations of static methods do not have implicit IInstanceReferenceOperations // as their receivers @@ -513,7 +552,7 @@ public override void VisitFunctionPointerInvocation(IFunctionPointerInvocationOp Assert.NotNull(signature); Assert.Same(((IFunctionPointerTypeSymbol)operation.Target.Type).Signature, signature); - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitArgument(IArgumentOperation operation) @@ -522,7 +561,7 @@ public override void VisitArgument(IArgumentOperation operation) Assert.Contains(operation.ArgumentKind, new[] { ArgumentKind.DefaultValue, ArgumentKind.Explicit, ArgumentKind.ParamArray }); var parameter = operation.Parameter; - Assert.Same(operation.Value, operation.Children.Single()); + Assert.Same(operation.Value, operation.ChildOperations.Single()); var inConversion = operation.InConversion; var outConversion = operation.OutConversion; @@ -535,19 +574,19 @@ public override void VisitArgument(IArgumentOperation operation) public override void VisitOmittedArgument(IOmittedArgumentOperation operation) { Assert.Equal(OperationKind.OmittedArgument, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitArrayElementReference(IArrayElementReferenceOperation operation) { Assert.Equal(OperationKind.ArrayElementReference, operation.Kind); - AssertEx.Equal(new[] { operation.ArrayReference }.Concat(operation.Indices), operation.Children); + AssertEx.Equal(new[] { operation.ArrayReference }.Concat(operation.Indices), operation.ChildOperations); } public override void VisitImplicitIndexerReference(IImplicitIndexerReferenceOperation operation) { Assert.Equal(OperationKind.ImplicitIndexerReference, operation.Kind); - AssertEx.Equal(new[] { operation.Instance, operation.Argument }, operation.Children); + AssertEx.Equal(new[] { operation.Instance, operation.Argument }, operation.ChildOperations); Assert.NotNull(operation.LengthSymbol); Assert.NotNull(operation.IndexerSymbol); @@ -556,7 +595,7 @@ public override void VisitImplicitIndexerReference(IImplicitIndexerReferenceOper internal override void VisitPointerIndirectionReference(IPointerIndirectionReferenceOperation operation) { Assert.Equal(OperationKind.None, operation.Kind); - Assert.Same(operation.Pointer, operation.Children.Single()); + Assert.Same(operation.Pointer, operation.ChildOperations.Single()); } public override void VisitLocalReference(ILocalReferenceOperation operation) @@ -564,20 +603,20 @@ public override void VisitLocalReference(ILocalReferenceOperation operation) Assert.Equal(OperationKind.LocalReference, operation.Kind); Assert.NotNull(operation.Local); var isDeclaration = operation.IsDeclaration; - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitParameterReference(IParameterReferenceOperation operation) { Assert.Equal(OperationKind.ParameterReference, operation.Kind); Assert.NotNull(operation.Parameter); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitInstanceReference(IInstanceReferenceOperation operation) { Assert.Equal(OperationKind.InstanceReference, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); var referenceKind = operation.ReferenceKind; } @@ -609,7 +648,7 @@ private void VisitMemberReference(IMemberReferenceOperation operation, IEnumerab children = additionalChildren; } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitFieldReference(IFieldReferenceOperation operation) @@ -650,26 +689,26 @@ public override void VisitEventAssignment(IEventAssignmentOperation operation) { Assert.Equal(OperationKind.EventAssignment, operation.Kind); var adds = operation.Adds; - AssertEx.Equal(new[] { operation.EventReference, operation.HandlerValue }, operation.Children); + AssertEx.Equal(new[] { operation.EventReference, operation.HandlerValue }, operation.ChildOperations); } public override void VisitConditionalAccess(IConditionalAccessOperation operation) { Assert.Equal(OperationKind.ConditionalAccess, operation.Kind); Assert.NotNull(operation.Type); - AssertEx.Equal(new[] { operation.Operation, operation.WhenNotNull }, operation.Children); + AssertEx.Equal(new[] { operation.Operation, operation.WhenNotNull }, operation.ChildOperations); } public override void VisitConditionalAccessInstance(IConditionalAccessInstanceOperation operation) { Assert.Equal(OperationKind.ConditionalAccessInstance, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } internal override void VisitPlaceholder(IPlaceholderOperation operation) { Assert.Equal(OperationKind.None, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitUnaryOperator(IUnaryOperation operation) @@ -681,7 +720,7 @@ public override void VisitUnaryOperator(IUnaryOperation operation) var isLifted = operation.IsLifted; var isChecked = operation.IsChecked; - Assert.Same(operation.Operand, operation.Children.Single()); + Assert.Same(operation.Operand, operation.ChildOperations.Single()); } public override void VisitBinaryOperator(IBinaryOperation operation) @@ -695,7 +734,7 @@ public override void VisitBinaryOperator(IBinaryOperation operation) var isChecked = operation.IsChecked; var isCompareText = operation.IsCompareText; - AssertEx.Equal(new[] { operation.LeftOperand, operation.RightOperand }, operation.Children); + AssertEx.Equal(new[] { operation.LeftOperand, operation.RightOperand }, operation.ChildOperations); } public override void VisitTupleBinaryOperator(ITupleBinaryOperation operation) @@ -704,7 +743,7 @@ public override void VisitTupleBinaryOperator(ITupleBinaryOperation operation) Assert.Equal(OperationKind.TupleBinary, operation.Kind); var binaryOperationKind = operation.OperatorKind; - AssertEx.Equal(new[] { operation.LeftOperand, operation.RightOperand }, operation.Children); + AssertEx.Equal(new[] { operation.LeftOperand, operation.RightOperand }, operation.ChildOperations); } public override void VisitConversion(IConversionOperation operation) @@ -730,7 +769,7 @@ public override void VisitConversion(IConversionOperation operation) break; } - Assert.Same(operation.Operand, operation.Children.Single()); + Assert.Same(operation.Operand, operation.ChildOperations.Single()); } public override void VisitConditional(IConditionalOperation operation) @@ -740,25 +779,25 @@ public override void VisitConditional(IConditionalOperation operation) if (operation.WhenFalse != null) { - AssertEx.Equal(new[] { operation.Condition, operation.WhenTrue, operation.WhenFalse }, operation.Children); + AssertEx.Equal(new[] { operation.Condition, operation.WhenTrue, operation.WhenFalse }, operation.ChildOperations); } else { - AssertEx.Equal(new[] { operation.Condition, operation.WhenTrue }, operation.Children); + AssertEx.Equal(new[] { operation.Condition, operation.WhenTrue }, operation.ChildOperations); } } public override void VisitCoalesce(ICoalesceOperation operation) { Assert.Equal(OperationKind.Coalesce, operation.Kind); - AssertEx.Equal(new[] { operation.Value, operation.WhenNull }, operation.Children); + AssertEx.Equal(new[] { operation.Value, operation.WhenNull }, operation.ChildOperations); var valueConversion = operation.ValueConversion; } public override void VisitCoalesceAssignment(ICoalesceAssignmentOperation operation) { Assert.Equal(OperationKind.CoalesceAssignment, operation.Kind); - AssertEx.Equal(new[] { operation.Target, operation.Value }, operation.Children); + AssertEx.Equal(new[] { operation.Target, operation.Value }, operation.ChildOperations); } public override void VisitIsType(IIsTypeOperation operation) @@ -766,35 +805,35 @@ public override void VisitIsType(IIsTypeOperation operation) Assert.Equal(OperationKind.IsType, operation.Kind); Assert.NotNull(operation.TypeOperand); bool isNegated = operation.IsNegated; - Assert.Same(operation.ValueOperand, operation.Children.Single()); + Assert.Same(operation.ValueOperand, operation.ChildOperations.Single()); } public override void VisitSizeOf(ISizeOfOperation operation) { Assert.Equal(OperationKind.SizeOf, operation.Kind); Assert.NotNull(operation.TypeOperand); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitTypeOf(ITypeOfOperation operation) { Assert.Equal(OperationKind.TypeOf, operation.Kind); Assert.NotNull(operation.TypeOperand); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitAnonymousFunction(IAnonymousFunctionOperation operation) { Assert.Equal(OperationKind.AnonymousFunction, operation.Kind); Assert.NotNull(operation.Symbol); - Assert.Same(operation.Body, operation.Children.Single()); + Assert.Same(operation.Body, operation.ChildOperations.Single()); } public override void VisitFlowAnonymousFunction(IFlowAnonymousFunctionOperation operation) { Assert.Equal(OperationKind.FlowAnonymousFunction, operation.Kind); Assert.NotNull(operation.Symbol); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitLocalFunction(ILocalFunctionOperation operation) @@ -804,7 +843,7 @@ public override void VisitLocalFunction(ILocalFunctionOperation operation) if (operation.Body != null) { - var children = operation.Children.ToImmutableArray(); + var children = operation.ChildOperations.ToImmutableArray(); Assert.Same(operation.Body, children[0]); if (operation.IgnoredBody != null) { @@ -819,26 +858,26 @@ public override void VisitLocalFunction(ILocalFunctionOperation operation) else { Assert.Null(operation.IgnoredBody); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } } public override void VisitLiteral(ILiteralOperation operation) { Assert.Equal(OperationKind.Literal, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitAwait(IAwaitOperation operation) { Assert.Equal(OperationKind.Await, operation.Kind); - Assert.Same(operation.Operation, operation.Children.Single()); + Assert.Same(operation.Operation, operation.ChildOperations.Single()); } public override void VisitNameOf(INameOfOperation operation) { Assert.Equal(OperationKind.NameOf, operation.Kind); - Assert.Same(operation.Argument, operation.Children.Single()); + Assert.Same(operation.Argument, operation.ChildOperations.Single()); } public override void VisitThrow(IThrowOperation operation) @@ -846,18 +885,18 @@ public override void VisitThrow(IThrowOperation operation) Assert.Equal(OperationKind.Throw, operation.Kind); if (operation.Exception == null) { - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } else { - Assert.Same(operation.Exception, operation.Children.Single()); + Assert.Same(operation.Exception, operation.ChildOperations.Single()); } } public override void VisitAddressOf(IAddressOfOperation operation) { Assert.Equal(OperationKind.AddressOf, operation.Kind); - Assert.Same(operation.Reference, operation.Children.Single()); + Assert.Same(operation.Reference, operation.ChildOperations.Single()); } public override void VisitObjectCreation(IObjectCreationOperation operation) @@ -882,13 +921,13 @@ public override void VisitObjectCreation(IObjectCreationOperation operation) children = children.Concat(new[] { operation.Initializer }); } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitAnonymousObjectCreation(IAnonymousObjectCreationOperation operation) { Assert.Equal(OperationKind.AnonymousObjectCreation, operation.Kind); - AssertEx.Equal(operation.Initializers, operation.Children); + AssertEx.Equal(operation.Initializers, operation.ChildOperations); foreach (var initializer in operation.Initializers) { var simpleAssignment = (ISimpleAssignmentOperation)initializer; @@ -909,37 +948,37 @@ public override void VisitDynamicObjectCreation(IDynamicObjectCreationOperation children = children.Concat(new[] { operation.Initializer }); } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitDynamicInvocation(IDynamicInvocationOperation operation) { Assert.Equal(OperationKind.DynamicInvocation, operation.Kind); - AssertEx.Equal(new[] { operation.Operation }.Concat(operation.Arguments), operation.Children); + AssertEx.Equal(new[] { operation.Operation }.Concat(operation.Arguments), operation.ChildOperations); } public override void VisitDynamicIndexerAccess(IDynamicIndexerAccessOperation operation) { Assert.Equal(OperationKind.DynamicIndexerAccess, operation.Kind); - AssertEx.Equal(new[] { operation.Operation }.Concat(operation.Arguments), operation.Children); + AssertEx.Equal(new[] { operation.Operation }.Concat(operation.Arguments), operation.ChildOperations); } public override void VisitObjectOrCollectionInitializer(IObjectOrCollectionInitializerOperation operation) { Assert.Equal(OperationKind.ObjectOrCollectionInitializer, operation.Kind); - AssertEx.Equal(operation.Initializers, operation.Children); + AssertEx.Equal(operation.Initializers, operation.ChildOperations); } public override void VisitMemberInitializer(IMemberInitializerOperation operation) { Assert.Equal(OperationKind.MemberInitializer, operation.Kind); - AssertEx.Equal(new[] { operation.InitializedMember, operation.Initializer }, operation.Children); + AssertEx.Equal(new[] { operation.InitializedMember, operation.Initializer }, operation.ChildOperations); } private void VisitSymbolInitializer(ISymbolInitializerOperation operation) { VisitLocals(operation.Locals); - Assert.Same(operation.Value, operation.Children.Single()); + Assert.Same(operation.Value, operation.ChildOperations.Single()); } public override void VisitFieldInitializer(IFieldInitializerOperation operation) @@ -986,19 +1025,19 @@ public override void VisitArrayCreation(IArrayCreationOperation operation) children = children.Concat(new[] { operation.Initializer }); } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitArrayInitializer(IArrayInitializerOperation operation) { Assert.Equal(OperationKind.ArrayInitializer, operation.Kind); Assert.Null(operation.Type); - AssertEx.Equal(operation.ElementValues, operation.Children); + AssertEx.Equal(operation.ElementValues, operation.ChildOperations); } private void VisitAssignment(IAssignmentOperation operation) { - AssertEx.Equal(new[] { operation.Target, operation.Value }, operation.Children); + AssertEx.Equal(new[] { operation.Target, operation.Value }, operation.ChildOperations); } public override void VisitSimpleAssignment(ISimpleAssignmentOperation operation) @@ -1044,13 +1083,13 @@ public override void VisitIncrementOrDecrement(IIncrementOrDecrementOperation op var isLifted = operation.IsLifted; var isChecked = operation.IsChecked; - Assert.Same(operation.Target, operation.Children.Single()); + Assert.Same(operation.Target, operation.ChildOperations.Single()); } public override void VisitParenthesized(IParenthesizedOperation operation) { Assert.Equal(OperationKind.Parenthesized, operation.Kind); - Assert.Same(operation.Operand, operation.Children.Single()); + Assert.Same(operation.Operand, operation.ChildOperations.Single()); } public override void VisitDynamicMemberReference(IDynamicMemberReferenceOperation operation) @@ -1067,18 +1106,18 @@ public override void VisitDynamicMemberReference(IDynamicMemberReferenceOperatio if (operation.Instance == null) { - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } else { - Assert.Same(operation.Instance, operation.Children.Single()); + Assert.Same(operation.Instance, operation.ChildOperations.Single()); } } public override void VisitDefaultValue(IDefaultValueOperation operation) { Assert.Equal(OperationKind.DefaultValue, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitTypeParameterObjectCreation(ITypeParameterObjectCreationOperation operation) @@ -1086,11 +1125,11 @@ public override void VisitTypeParameterObjectCreation(ITypeParameterObjectCreati Assert.Equal(OperationKind.TypeParameterObjectCreation, operation.Kind); if (operation.Initializer == null) { - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } else { - Assert.Same(operation.Initializer, operation.Children.Single()); + Assert.Same(operation.Initializer, operation.ChildOperations.Single()); } } @@ -1099,11 +1138,11 @@ internal override void VisitNoPiaObjectCreation(INoPiaObjectCreationOperation op Assert.Equal(OperationKind.None, operation.Kind); if (operation.Initializer == null) { - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } else { - Assert.Same(operation.Initializer, operation.Children.Single()); + Assert.Same(operation.Initializer, operation.ChildOperations.Single()); } } @@ -1116,13 +1155,13 @@ public override void VisitTuple(ITupleOperation operation) { Assert.Equal(OperationKind.Tuple, operation.Kind); var naturalType = operation.NaturalType; - AssertEx.Equal(operation.Elements, operation.Children); + AssertEx.Equal(operation.Elements, operation.ChildOperations); } public override void VisitInterpolatedString(IInterpolatedStringOperation operation) { Assert.Equal(OperationKind.InterpolatedString, operation.Kind); - AssertEx.Equal(operation.Parts, operation.Children); + AssertEx.Equal(operation.Parts, operation.ChildOperations); } public override void VisitInterpolatedStringText(IInterpolatedStringTextOperation operation) @@ -1132,7 +1171,7 @@ public override void VisitInterpolatedStringText(IInterpolatedStringTextOperatio { Assert.Equal(OperationKind.Literal, ((IConversionOperation)operation.Text).Operand.Kind); } - Assert.Same(operation.Text, operation.Children.Single()); + Assert.Same(operation.Text, operation.ChildOperations.Single()); } public override void VisitInterpolation(IInterpolationOperation operation) @@ -1153,14 +1192,14 @@ public override void VisitInterpolation(IInterpolationOperation operation) children = children.Concat(new[] { operation.FormatString }); } - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitInterpolatedStringHandlerCreation(IInterpolatedStringHandlerCreationOperation operation) { Assert.Equal(OperationKind.InterpolatedStringHandlerCreation, operation.Kind); IEnumerable children = new[] { operation.HandlerCreation, operation.Content }; - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); Assert.True(operation.HandlerCreation is IObjectCreationOperation or IDynamicObjectCreationOperation or IInvalidOperation); Assert.True(operation.Content is IInterpolatedStringAdditionOperation or IInterpolatedStringOperation); _ = operation.HandlerCreationHasSuccessParameter; @@ -1170,7 +1209,7 @@ public override void VisitInterpolatedStringHandlerCreation(IInterpolatedStringH public override void VisitInterpolatedStringAddition(IInterpolatedStringAdditionOperation operation) { Assert.Equal(OperationKind.InterpolatedStringAddition, operation.Kind); - AssertEx.Equal(new[] { operation.Left, operation.Right }, operation.Children); + AssertEx.Equal(new[] { operation.Left, operation.Right }, operation.ChildOperations); Assert.True(operation.Left is IInterpolatedStringAdditionOperation or IInterpolatedStringOperation); Assert.True(operation.Right is IInterpolatedStringAdditionOperation or IInterpolatedStringOperation); } @@ -1207,7 +1246,7 @@ public override void VisitConstantPattern(IConstantPatternOperation operation) { Assert.Equal(OperationKind.ConstantPattern, operation.Kind); VisitPatternCommon(operation); - Assert.Same(operation.Value, operation.Children.Single()); + Assert.Same(operation.Value, operation.ChildOperations.Single()); } public override void VisitRelationalPattern(IRelationalPatternOperation operation) @@ -1220,7 +1259,7 @@ Operations.BinaryOperatorKind.GreaterThanOrEqual or Operations.BinaryOperatorKind.Equals or // Error cases Operations.BinaryOperatorKind.NotEquals); VisitPatternCommon(operation); - Assert.Same(operation.Value, operation.Children.Single()); + Assert.Same(operation.Value, operation.ChildOperations.Single()); } public override void VisitBinaryPattern(IBinaryPatternOperation operation) @@ -1228,7 +1267,7 @@ public override void VisitBinaryPattern(IBinaryPatternOperation operation) Assert.Equal(OperationKind.BinaryPattern, operation.Kind); VisitPatternCommon(operation); Assert.True(operation.OperatorKind switch { Operations.BinaryOperatorKind.Or => true, Operations.BinaryOperatorKind.And => true, _ => false }); - var children = operation.Children.ToArray(); + var children = operation.ChildOperations.ToArray(); Assert.Equal(2, children.Length); Assert.Same(operation.LeftPattern, children[0]); Assert.Same(operation.RightPattern, children[1]); @@ -1238,7 +1277,7 @@ public override void VisitNegatedPattern(INegatedPatternOperation operation) { Assert.Equal(OperationKind.NegatedPattern, operation.Kind); VisitPatternCommon(operation); - Assert.Same(operation.Pattern, operation.Children.Single()); + Assert.Same(operation.Pattern, operation.ChildOperations.Single()); } public override void VisitTypePattern(ITypePatternOperation operation) @@ -1246,7 +1285,7 @@ public override void VisitTypePattern(ITypePatternOperation operation) Assert.Equal(OperationKind.TypePattern, operation.Kind); Assert.NotNull(operation.MatchedType); VisitPatternCommon(operation); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitDeclarationPattern(IDeclarationPatternOperation operation) @@ -1279,7 +1318,7 @@ public override void VisitDeclarationPattern(IDeclarationPatternOperation operat Assert.Null(operation.DeclaredSymbol); } - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitSlicePattern(ISlicePatternOperation operation) @@ -1289,11 +1328,11 @@ public override void VisitSlicePattern(ISlicePatternOperation operation) if (operation.Pattern != null) { - Assert.Same(operation.Pattern, operation.Children.Single()); + Assert.Same(operation.Pattern, operation.ChildOperations.Single()); } else { - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } } @@ -1312,7 +1351,7 @@ public override void VisitListPattern(IListPatternOperation operation) } IEnumerable children = operation.Patterns.Cast(); - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitRecursivePattern(IRecursivePatternOperation operation) @@ -1356,14 +1395,14 @@ public override void VisitRecursivePattern(IRecursivePatternOperation operation) IEnumerable children = operation.DeconstructionSubpatterns.Cast(); children = children.Concat(operation.PropertySubpatterns); - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitPropertySubpattern(IPropertySubpatternOperation operation) { Assert.NotNull(operation.Pattern); var children = new IOperation[] { operation.Member, operation.Pattern }; - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); if (operation.Member.Kind == OperationKind.Invalid) { @@ -1392,7 +1431,7 @@ public override void VisitSwitchExpression(ISwitchExpressionOperation operation) Assert.Equal(OperationKind.SwitchExpression, operation.Kind); Assert.NotNull(operation.Value); var children = operation.Arms.Cast().Prepend(operation.Value); - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitSwitchExpressionArm(ISwitchExpressionArmOperation operation) @@ -1406,13 +1445,13 @@ public override void VisitSwitchExpressionArm(ISwitchExpressionArmOperation oper var children = operation.Guard == null ? new[] { operation.Pattern, operation.Value } : new[] { operation.Pattern, operation.Guard, operation.Value }; - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } public override void VisitIsPattern(IIsPatternOperation operation) { Assert.Equal(OperationKind.IsPattern, operation.Kind); - AssertEx.Equal(new[] { operation.Value, operation.Pattern }, operation.Children); + AssertEx.Equal(new[] { operation.Value, operation.Pattern }, operation.ChildOperations); } public override void VisitPatternCaseClause(IPatternCaseClauseOperation operation) @@ -1423,24 +1462,24 @@ public override void VisitPatternCaseClause(IPatternCaseClauseOperation operatio if (operation.Guard != null) { - AssertEx.Equal(new[] { operation.Pattern, operation.Guard }, operation.Children); + AssertEx.Equal(new[] { operation.Pattern, operation.Guard }, operation.ChildOperations); } else { - Assert.Same(operation.Pattern, operation.Children.Single()); + Assert.Same(operation.Pattern, operation.ChildOperations.Single()); } } public override void VisitTranslatedQuery(ITranslatedQueryOperation operation) { Assert.Equal(OperationKind.TranslatedQuery, operation.Kind); - Assert.Same(operation.Operation, operation.Children.Single()); + Assert.Same(operation.Operation, operation.ChildOperations.Single()); } public override void VisitDeclarationExpression(IDeclarationExpressionOperation operation) { Assert.Equal(OperationKind.DeclarationExpression, operation.Kind); - Assert.Same(operation.Expression, operation.Children.Single()); + Assert.Same(operation.Expression, operation.ChildOperations.Single()); } public override void VisitDeconstructionAssignment(IDeconstructionAssignmentOperation operation) @@ -1452,20 +1491,20 @@ public override void VisitDeconstructionAssignment(IDeconstructionAssignmentOper public override void VisitDelegateCreation(IDelegateCreationOperation operation) { Assert.Equal(OperationKind.DelegateCreation, operation.Kind); - Assert.Same(operation.Target, operation.Children.Single()); + Assert.Same(operation.Target, operation.ChildOperations.Single()); } public override void VisitRaiseEvent(IRaiseEventOperation operation) { Assert.Equal(OperationKind.RaiseEvent, operation.Kind); - AssertEx.Equal(new IOperation[] { operation.EventReference }.Concat(operation.Arguments), operation.Children); + AssertEx.Equal(new IOperation[] { operation.EventReference }.Concat(operation.Arguments), operation.ChildOperations); } public override void VisitRangeCaseClause(IRangeCaseClauseOperation operation) { VisitCaseClauseOperation(operation); Assert.Equal(CaseKind.Range, operation.CaseKind); - AssertEx.Equal(new[] { operation.MinimumValue, operation.MaximumValue }, operation.Children); + AssertEx.Equal(new[] { operation.MinimumValue, operation.MaximumValue }, operation.ChildOperations); } public override void VisitConstructorBodyOperation(IConstructorBodyOperation operation) @@ -1491,7 +1530,7 @@ public override void VisitConstructorBodyOperation(IConstructorBodyOperation ope builder.Add(operation.ExpressionBody); } - AssertEx.Equal(builder, operation.Children); + AssertEx.Equal(builder, operation.ChildOperations); builder.Free(); } @@ -1504,27 +1543,27 @@ public override void VisitMethodBodyOperation(IMethodBodyOperation operation) { if (operation.ExpressionBody != null) { - AssertEx.Equal(new[] { operation.BlockBody, operation.ExpressionBody }, operation.Children); + AssertEx.Equal(new[] { operation.BlockBody, operation.ExpressionBody }, operation.ChildOperations); } else { - Assert.Same(operation.BlockBody, operation.Children.Single()); + Assert.Same(operation.BlockBody, operation.ChildOperations.Single()); } } else if (operation.ExpressionBody != null) { - Assert.Same(operation.ExpressionBody, operation.Children.Single()); + Assert.Same(operation.ExpressionBody, operation.ChildOperations.Single()); } else { - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } } public override void VisitDiscardOperation(IDiscardOperation operation) { Assert.Equal(OperationKind.Discard, operation.Kind); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); var discardSymbol = operation.DiscardSymbol; Assert.Equal(operation.Type, discardSymbol.Type); @@ -1534,14 +1573,14 @@ public override void VisitDiscardPattern(IDiscardPatternOperation operation) { Assert.Equal(OperationKind.DiscardPattern, operation.Kind); VisitPatternCommon(operation); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitFlowCapture(IFlowCaptureOperation operation) { Assert.Equal(OperationKind.FlowCapture, operation.Kind); Assert.True(operation.IsImplicit); - Assert.Same(operation.Value, operation.Children.Single()); + Assert.Same(operation.Value, operation.ChildOperations.Single()); switch (operation.Value.Kind) { @@ -1573,28 +1612,28 @@ public override void VisitFlowCaptureReference(IFlowCaptureReferenceOperation op { Assert.Equal(OperationKind.FlowCaptureReference, operation.Kind); Assert.True(operation.IsImplicit); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitIsNull(IIsNullOperation operation) { Assert.Equal(OperationKind.IsNull, operation.Kind); Assert.True(operation.IsImplicit); - Assert.Same(operation.Operand, operation.Children.Single()); + Assert.Same(operation.Operand, operation.ChildOperations.Single()); } public override void VisitCaughtException(ICaughtExceptionOperation operation) { Assert.Equal(OperationKind.CaughtException, operation.Kind); Assert.True(operation.IsImplicit); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); } public override void VisitStaticLocalInitializationSemaphore(IStaticLocalInitializationSemaphoreOperation operation) { Assert.Equal(OperationKind.StaticLocalInitializationSemaphore, operation.Kind); Assert.True(operation.IsImplicit); - Assert.Empty(operation.Children); + Assert.Empty(operation.ChildOperations); Assert.NotNull(operation.Local); Assert.True(operation.Local.IsStatic); } @@ -1603,7 +1642,7 @@ public override void VisitRangeOperation(IRangeOperation operation) { Assert.Equal(OperationKind.Range, operation.Kind); - IOperation[] children = operation.Children.ToArray(); + IOperation[] children = operation.ChildOperations.ToArray(); int index = 0; @@ -1623,20 +1662,20 @@ public override void VisitRangeOperation(IRangeOperation operation) public override void VisitReDim(IReDimOperation operation) { Assert.Equal(OperationKind.ReDim, operation.Kind); - AssertEx.Equal(operation.Clauses, operation.Children); + AssertEx.Equal(operation.Clauses, operation.ChildOperations); var preserve = operation.Preserve; } public override void VisitReDimClause(IReDimClauseOperation operation) { Assert.Equal(OperationKind.ReDimClause, operation.Kind); - AssertEx.Equal(SpecializedCollections.SingletonEnumerable(operation.Operand).Concat(operation.DimensionSizes), operation.Children); + AssertEx.Equal(SpecializedCollections.SingletonEnumerable(operation.Operand).Concat(operation.DimensionSizes), operation.ChildOperations); } public override void VisitUsingDeclaration(IUsingDeclarationOperation operation) { Assert.NotNull(operation.DeclarationGroup); - AssertEx.Equal(SpecializedCollections.SingletonEnumerable(operation.DeclarationGroup), operation.Children); + AssertEx.Equal(SpecializedCollections.SingletonEnumerable(operation.DeclarationGroup), operation.ChildOperations); Assert.True(operation.DeclarationGroup.IsImplicit); Assert.Null(operation.Type); Assert.False(operation.ConstantValue.HasValue); @@ -1659,7 +1698,7 @@ public override void VisitWith(IWithOperation operation) Assert.Equal(OperationKind.With, operation.Kind); _ = operation.CloneMethod; IEnumerable children = SpecializedCollections.SingletonEnumerable(operation.Operand).Concat(operation.Initializer); - AssertEx.Equal(children, operation.Children); + AssertEx.Equal(children, operation.ChildOperations); } } } diff --git a/src/Compilers/Test/Core/CompilationVerifier.cs b/src/Compilers/Test/Core/CompilationVerifier.cs index 1ed62d8b828c8..1ed7b012db3a8 100644 --- a/src/Compilers/Test/Core/CompilationVerifier.cs +++ b/src/Compilers/Test/Core/CompilationVerifier.cs @@ -7,15 +7,17 @@ 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.PortableExecutable; using System.Runtime.CompilerServices; using System.Xml.Linq; using ICSharpCode.Decompiler.Metadata; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.DiaSymReader.Tools; using Roslyn.Test.Utilities; using Xunit; @@ -196,13 +198,24 @@ public void VerifyTypeIL(string typeName, string expected) AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, output.ToString(), escapeQuotes: false); } - public void Emit(string expectedOutput, int? expectedReturnCode, string[] args, IEnumerable manifestResources, EmitOptions emitOptions, Verification peVerify, SignatureDescription[] expectedSignatures) + public void Emit( + string expectedOutput, + bool trimOutput, + int? expectedReturnCode, + string[] args, + IEnumerable manifestResources, + EmitOptions emitOptions, + Verification peVerify, + SignatureDescription[] expectedSignatures) { using var testEnvironment = RuntimeEnvironmentFactory.Create(_dependencies); string mainModuleName = Emit(testEnvironment, manifestResources, emitOptions); _allModuleData = testEnvironment.GetAllModuleData(); testEnvironment.Verify(peVerify); +#if NETCOREAPP + ILVerify(peVerify); +#endif if (expectedSignatures != null) { @@ -211,7 +224,7 @@ public void Emit(string expectedOutput, int? expectedReturnCode, string[] args, if (expectedOutput != null || expectedReturnCode != null) { - var returnCode = testEnvironment.Execute(mainModuleName, args, expectedOutput); + var returnCode = testEnvironment.Execute(mainModuleName, args, expectedOutput, trimOutput); if (expectedReturnCode is int exCode) { @@ -220,6 +233,133 @@ public void Emit(string expectedOutput, int? expectedReturnCode, string[] args, } } + private sealed class Resolver : ILVerify.ResolverBase + { + private readonly Dictionary> _imagesByName; + + internal Resolver(Dictionary> imagesByName) + { + _imagesByName = imagesByName; + } + + protected override PEReader ResolveCore(string simpleName) + { + if (_imagesByName.TryGetValue(simpleName, out var image)) + { + return new PEReader(image); + } + + throw new Exception($"ILVerify was not able to resolve a module named '{simpleName}'"); + } + } + + private void ILVerify(Verification verification) + { + if (verification == Verification.Skipped) + { + return; + } + + var imagesByName = new Dictionary>(StringComparer.OrdinalIgnoreCase); + foreach (var module in _allModuleData) + { + string name = module.SimpleName; + if (imagesByName.ContainsKey(name)) + { + if ((verification & Verification.FailsILVerify) != 0) + { + return; + } + + throw new Exception($"Multiple modules named '{name}' were found"); + } + imagesByName.Add(name, module.Image); + } + + var resolver = new Resolver(imagesByName); + var verifier = new ILVerify.Verifier(resolver); + var mscorlibModule = _allModuleData.SingleOrDefault(m => m.IsCorLib); + if (mscorlibModule is null) + { + if ((verification & Verification.FailsILVerify) != 0) + { + return; + } + + throw new Exception("No corlib found"); + } + + // Main module is the first one + var mainModuleReader = resolver.Resolve(_allModuleData[0].SimpleName); + + var (succeeded, errorMessage) = verify(verifier, mscorlibModule.SimpleName, mainModuleReader); + + switch (succeeded, (verification & Verification.FailsILVerify) == 0) + { + case (true, true): + return; + case (true, false): + throw new Exception("IL Verify succeeded unexpectedly"); + case (false, false): + return; + case (false, true): + throw new Exception("IL Verify failed unexpectedly: \r\n" + errorMessage); + } + + static (bool, string) verify(ILVerify.Verifier verifier, string corlibName, PEReader mainModule) + { + IEnumerable result = null; + int errorCount = 0; + try + { + verifier.SetSystemModuleName(new AssemblyName(corlibName)); + result = verifier.Verify(mainModule); + errorCount = result.Count(); + } + catch (Exception e) + { + return (false, e.Message); + } + + if (errorCount > 0) + { + return (false, printVerificationResult(result)); + } + + return (true, string.Empty); + } + + static string printVerificationResult(IEnumerable result) + { + return string.Join("\r\n", result.Select(r => r.Message + printErrorArguments(r.ErrorArguments))); + } + + static string printErrorArguments(ILVerify.ErrorArgument[] errorArguments) + { + if (errorArguments is null + || errorArguments.Length == 0) + { + return ""; + } + + var pooledBuilder = PooledStringBuilder.GetInstance(); + var builder = pooledBuilder.Builder; + builder.Append(" { "); + var x = errorArguments.Select(a => a.Name + " = " + a.Value.ToString()).ToArray(); + for (int i = 0; i < x.Length; i++) + { + if (i > 0) + { + builder.Append(", "); + } + builder.Append(x[i]); + } + builder.Append(" }"); + + return pooledBuilder.ToStringAndFree(); + } + } + // TODO(tomat): Fold into CompileAndVerify. // Replace bool verify parameter with string[] expectedPeVerifyOutput. If null, no verification. If empty verify have to succeed. Otherwise compare errors. public void EmitAndVerify(params string[] expectedPeVerifyOutput) diff --git a/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs b/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs index b6ec923ec6c7a..90cb65fdba517 100644 --- a/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs +++ b/src/Compilers/Test/Core/Diagnostics/CommonDiagnosticAnalyzers.cs @@ -785,6 +785,7 @@ public sealed class AnalyzerWithInvalidDiagnosticLocation : DiagnosticAnalyzer { private readonly Location _invalidLocation; private readonly ActionKind _actionKind; + private readonly bool _testInvalidAdditionalLocation; public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor( "ID", @@ -805,17 +806,20 @@ public enum ActionKind SyntaxTree } - public AnalyzerWithInvalidDiagnosticLocation(SyntaxTree treeInAnotherCompilation, ActionKind actionKind) + public AnalyzerWithInvalidDiagnosticLocation(SyntaxTree treeInAnotherCompilation, ActionKind actionKind, bool testInvalidAdditionalLocation) { _invalidLocation = treeInAnotherCompilation.GetRoot().GetLocation(); _actionKind = actionKind; + _testInvalidAdditionalLocation = testInvalidAdditionalLocation; } private void ReportDiagnostic(Action addDiagnostic, ActionKind actionKindBeingRun) { if (_actionKind == actionKindBeingRun) { - var diagnostic = Diagnostic.Create(Descriptor, _invalidLocation); + var diagnostic = _testInvalidAdditionalLocation ? + Diagnostic.Create(Descriptor, Location.None, additionalLocations: new[] { _invalidLocation }) : + Diagnostic.Create(Descriptor, _invalidLocation); addDiagnostic(diagnostic); } } diff --git a/src/Compilers/Test/Core/ExceptionHelper.cs b/src/Compilers/Test/Core/ExceptionHelper.cs index c41608a7c7b56..8e1436698777a 100644 --- a/src/Compilers/Test/Core/ExceptionHelper.cs +++ b/src/Compilers/Test/Core/ExceptionHelper.cs @@ -25,11 +25,12 @@ internal static string GetMessageFromResult(IEnumerable diagnostics, return sb.ToString(); } - internal static string GetMessageFromResult(string output, string exePath) + internal static string GetMessageFromResult(string output, string exePath, bool isIlVerify = false) { StringBuilder sb = new StringBuilder(); sb.AppendLine(); - sb.Append("PeVerify failed for assembly '"); + string tool = isIlVerify ? "ILVerify" : "PEVerify"; + sb.Append($"{tool} failed for assembly '"); sb.Append(exePath); sb.AppendLine("':"); sb.AppendLine(output); diff --git a/src/Compilers/Test/Core/Metadata/ModuleData.cs b/src/Compilers/Test/Core/Metadata/ModuleData.cs index 712aaa4ab92e3..ddaa3ef24b9db 100644 --- a/src/Compilers/Test/Core/Metadata/ModuleData.cs +++ b/src/Compilers/Test/Core/Metadata/ModuleData.cs @@ -56,36 +56,40 @@ public sealed class ModuleData public readonly ImmutableArray Image; public readonly ImmutableArray Pdb; public readonly bool InMemoryModule; + public readonly bool IsCorLib; public string SimpleName => Id.SimpleName; public string FullName => Id.FullName; public Guid Mvid => Id.Mvid; - public ModuleData(string netModuleName, ImmutableArray image, ImmutableArray pdb, bool inMemoryModule) + public ModuleData(string netModuleName, ImmutableArray image, ImmutableArray pdb, bool inMemoryModule, bool isCorLib) { this.Id = new ModuleDataId(netModuleName, netModuleName, GetMvid(image)); this.Kind = OutputKind.NetModule; this.Image = image; this.Pdb = pdb; this.InMemoryModule = inMemoryModule; + this.IsCorLib = isCorLib; } - public ModuleData(AssemblyIdentity identity, OutputKind kind, ImmutableArray image, ImmutableArray pdb, bool inMemoryModule) + public ModuleData(AssemblyIdentity identity, OutputKind kind, ImmutableArray image, ImmutableArray pdb, bool inMemoryModule, bool isCorLib) { this.Id = new ModuleDataId(identity.Name, identity.GetDisplayName(), GetMvid(image)); this.Kind = kind; this.Image = image; this.Pdb = pdb; this.InMemoryModule = inMemoryModule; + this.IsCorLib = isCorLib; } - public ModuleData(ModuleDataId id, OutputKind kind, ImmutableArray image, ImmutableArray pdb, bool inMemoryModule) + public ModuleData(ModuleDataId id, OutputKind kind, ImmutableArray image, ImmutableArray pdb, bool inMemoryModule, bool isCorLib) { this.Id = id; this.Kind = kind; this.Image = image; this.Pdb = pdb; this.InMemoryModule = inMemoryModule; + this.IsCorLib = isCorLib; } private static Guid GetMvid(ImmutableArray image) diff --git a/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj b/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj index 25151e909aae4..c7149688b8f4f 100644 --- a/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj +++ b/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj @@ -105,6 +105,7 @@ + diff --git a/src/Compilers/Test/Core/Mocks/TestAdditionalText.cs b/src/Compilers/Test/Core/Mocks/TestAdditionalText.cs index a079a1f11e622..4153953648c0a 100644 --- a/src/Compilers/Test/Core/Mocks/TestAdditionalText.cs +++ b/src/Compilers/Test/Core/Mocks/TestAdditionalText.cs @@ -11,21 +11,21 @@ namespace Roslyn.Test.Utilities { public sealed class TestAdditionalText : AdditionalText { - private readonly SourceText _text; + private readonly SourceText? _text; - public TestAdditionalText(string path, SourceText text) + public TestAdditionalText(string path, SourceText? text) { Path = path; _text = text; } - public TestAdditionalText(string text = "", Encoding? encoding = null, string path = "dummy") - : this(path, new StringText(text, encoding)) + public TestAdditionalText(string text = "", Encoding? encoding = null, string path = "dummy", SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithm.Sha1) + : this(path, new StringText(text, encoding, checksumAlgorithm: checksumAlgorithm)) { } public override string Path { get; } - public override SourceText GetText(CancellationToken cancellationToken = default) => _text; + public override SourceText? GetText(CancellationToken cancellationToken = default) => _text; } } diff --git a/src/Compilers/Test/Core/ModuleInitializer.cs b/src/Compilers/Test/Core/ModuleInitializer.cs index 6e592c35225c8..2b1bcb4d22081 100644 --- a/src/Compilers/Test/Core/ModuleInitializer.cs +++ b/src/Compilers/Test/Core/ModuleInitializer.cs @@ -17,10 +17,6 @@ internal static void Initialize() { Trace.Listeners.Clear(); Trace.Listeners.Add(new ThrowingTraceListener()); - - // Make sure we load DSRN from the directory containing the unit tests and not from a runtime directory on .NET 5+. - Environment.SetEnvironmentVariable("MICROSOFT_DIASYMREADER_NATIVE_ALT_LOAD_PATH", Path.GetDirectoryName(typeof(ModuleInitializer).Assembly.Location)); - Environment.SetEnvironmentVariable("MICROSOFT_DIASYMREADER_NATIVE_USE_ALT_LOAD_PATH_ONLY", "1"); } } } diff --git a/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs b/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs index f8935f6337a90..dbe385dd965c5 100644 --- a/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs +++ b/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs @@ -6,9 +6,9 @@ #if NETCOREAPP using System; -using System.Linq; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; @@ -52,12 +52,15 @@ public void Emit( { var mainImage = mainOutput.Value.Assembly; var mainPdb = mainOutput.Value.Pdb; + var corLibIdentity = mainCompilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly.Identity; + var identity = mainCompilation.Assembly.Identity; _emitData.MainModule = new ModuleData( - mainCompilation.Assembly.Identity, + identity, mainCompilation.Options.OutputKind, mainImage, pdb: usePdbForDebugging ? mainPdb : default(ImmutableArray), - inMemoryModule: true); + inMemoryModule: true, + isCorLib: corLibIdentity == identity); _emitData.MainModulePdb = mainPdb; _emitData.AllModuleData = dependencies; @@ -77,18 +80,19 @@ public void Emit( } } - public int Execute(string moduleName, string[] args, string expectedOutput) + public int Execute(string moduleName, string[] args, string expectedOutput, bool trimOutput = true) { var emitData = GetEmitData(); emitData.RuntimeData.ExecuteRequested = true; - var (ExitCode, Output) = emitData.LoadContext.Execute(GetMainImage(), args, expectedOutput?.Length); + var (exitCode, output) = emitData.LoadContext.Execute(GetMainImage(), args, expectedOutput?.Length); - if (expectedOutput != null && expectedOutput.Trim() != Output.Trim()) + if (expectedOutput != null) { - throw new ExecutionException(expectedOutput, Output, moduleName); + if (trimOutput ? (expectedOutput.Trim() != output.Trim()) : (expectedOutput != output)) + throw new ExecutionException(expectedOutput, output, moduleName); } - return ExitCode; + return exitCode; } private EmitData GetEmitData() => _emitData ?? throw new InvalidOperationException("Must call Emit before calling this method"); @@ -106,9 +110,6 @@ public SortedSet GetMemberSignaturesFromMetadata(string fullyQualifiedTy public void Verify(Verification verification) { - var emitData = GetEmitData(); - emitData.RuntimeData.PeverifyRequested = true; - // TODO(https://github.com/dotnet/coreclr/issues/295): Implement peverify } public string[] VerifyModules(string[] modulesToVerify) diff --git a/src/Compilers/Test/Core/Platform/Desktop/DesktopRuntimeEnvironment.cs b/src/Compilers/Test/Core/Platform/Desktop/DesktopRuntimeEnvironment.cs index 87285a50330f5..dd534dc1963da 100644 --- a/src/Compilers/Test/Core/Platform/Desktop/DesktopRuntimeEnvironment.cs +++ b/src/Compilers/Test/Core/Platform/Desktop/DesktopRuntimeEnvironment.cs @@ -9,13 +9,17 @@ 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.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Roslyn.Utilities; @@ -210,12 +214,15 @@ public void Emit( { var mainImage = mainOutput.Value.Assembly; var mainPdb = mainOutput.Value.Pdb; + var corLibIdentity = mainCompilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly.Identity; + var identity = mainCompilation.Assembly.Identity; _emitData.MainModule = new ModuleData( - mainCompilation.Assembly.Identity, + identity, mainCompilation.Options.OutputKind, mainImage, pdb: usePdbForDebugging ? mainPdb : default(ImmutableArray), - inMemoryModule: true); + inMemoryModule: true, + isCorLib: corLibIdentity == identity); _emitData.MainModulePdb = mainPdb; _emitData.AllModuleData = dependencies; @@ -235,18 +242,21 @@ public void Emit( } } - public int Execute(string moduleName, string[] args, string expectedOutput) + public int Execute(string moduleName, string[] args, string expectedOutput, bool trimOutput = true) { try { var emitData = GetEmitData(); emitData.RuntimeData.ExecuteRequested = true; - var resultCode = emitData.Manager.Execute(moduleName, args, expectedOutput?.Length, out var output); + var resultCode = emitData.Manager.Execute(moduleName, args, expectedOutputLength: expectedOutput?.Length, out var output); - if (expectedOutput != null && expectedOutput.Trim() != output.Trim()) + if (expectedOutput != null) { - GetEmitData().Manager.DumpAssemblyData(out var dumpDir); - throw new ExecutionException(expectedOutput, output, dumpDir); + if (trimOutput ? (expectedOutput.Trim() != output.Trim()) : (expectedOutput != output)) + { + GetEmitData().Manager.DumpAssemblyData(out var dumpDir); + throw new ExecutionException(expectedOutput, output, moduleName); + } } return resultCode; @@ -306,15 +316,16 @@ public void Verify(Verification verification) return; } - var shouldSucceed = verification == Verification.Passes; + var shouldSucceed = (verification & Verification.FailsPEVerify) == 0; var emitData = GetEmitData(); + try { emitData.RuntimeData.PeverifyRequested = true; emitData.Manager.PeVerifyModules(new[] { emitData.MainModule.FullName }, throwOnError: true); if (!shouldSucceed) { - throw new Exception("Verification succeeded unexpectedly"); + throw new Exception("PE Verify succeeded unexpectedly"); } } catch (RuntimePeVerifyException ex) diff --git a/src/Compilers/Test/Core/Platform/Desktop/RuntimeModuleData.cs b/src/Compilers/Test/Core/Platform/Desktop/RuntimeModuleData.cs index a5d65631049e3..bf6ea756e2ed0 100644 --- a/src/Compilers/Test/Core/Platform/Desktop/RuntimeModuleData.cs +++ b/src/Compilers/Test/Core/Platform/Desktop/RuntimeModuleData.cs @@ -67,7 +67,8 @@ private RuntimeModuleData(SerializationInfo info, StreamingContext context) var image = info.GetByteArray(nameof(ModuleData.Image)); var pdb = info.GetByteArray(nameof(ModuleData.Pdb)); var inMemoryModule = info.GetBoolean(nameof(ModuleData.InMemoryModule)); - Data = new ModuleData(id.Id, kind, image, pdb, inMemoryModule); + var isCorLib = info.GetBoolean(nameof(ModuleData.IsCorLib)); + Data = new ModuleData(id.Id, kind, image, pdb, inMemoryModule, isCorLib); } public void GetObjectData(SerializationInfo info, StreamingContext context) @@ -77,6 +78,7 @@ public void GetObjectData(SerializationInfo info, StreamingContext context) info.AddByteArray(nameof(ModuleData.Image), Data.Image); info.AddByteArray(nameof(ModuleData.Pdb), Data.Pdb); info.AddValue(nameof(ModuleData.InMemoryModule), Data.InMemoryModule); + info.AddValue(nameof(ModuleData.IsCorLib), Data.IsCorLib); } } } diff --git a/src/Compilers/Test/Core/TestBase.cs b/src/Compilers/Test/Core/TestBase.cs index b00ee4b1cc24f..6f47e4ad8a47f 100644 --- a/src/Compilers/Test/Core/TestBase.cs +++ b/src/Compilers/Test/Core/TestBase.cs @@ -151,6 +151,11 @@ private static MetadataReference GetOrCreateMetadataReference(ref MetadataRefere LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemCoreRef_v4_0_30319_17929 => s_systemCoreRef_v4_0_30319_17929.Value; + private static readonly Lazy s_systemRuntimeSerializationRef_v4_0_30319_17929 = new Lazy( + () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntimeSerialization).GetReference(display: "System.Runtime.Serialization.v4_0_30319_17929.dll"), + LazyThreadSafetyMode.PublicationOnly); + public static MetadataReference SystemRuntimeSerializationRef_v4_0_30319_17929 => s_systemRuntimeSerializationRef_v4_0_30319_17929.Value; + private static readonly Lazy s_systemCoreRef_v46 = new Lazy( () => AssemblyMetadata.CreateFromImage(ResourcesNet461.SystemCore).GetReference(display: "System.Core.v4_6_1038_0.dll"), LazyThreadSafetyMode.PublicationOnly); diff --git a/src/Compilers/Test/Core/TestResource.resx b/src/Compilers/Test/Core/TestResource.resx index d6297d3136bd1..b07d4676f2501 100644 --- a/src/Compilers/Test/Core/TestResource.resx +++ b/src/Compilers/Test/Core/TestResource.resx @@ -866,6 +866,14 @@ namespace Comments.XmlComments.UndocumentedKeywords } } +class RawStringLiterals +{ + public const string SingleLine = """single line"""; + public const string MultiLine = """ + Multi line + """; +} + #line 6 #line 2 "test.cs" #line default diff --git a/src/Compilers/Test/Core/TestableCompiler.cs b/src/Compilers/Test/Core/TestableCompiler.cs new file mode 100644 index 0000000000000..a8cc3c9873f31 --- /dev/null +++ b/src/Compilers/Test/Core/TestableCompiler.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; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.VisualBasic; + +namespace Roslyn.Test.Utilities +{ + internal readonly struct TestableCompilerFile + { + public string FilePath { get; } + public TestableFile TestableFile { get; } + public List Contents => TestableFile.Contents; + + public TestableCompilerFile(string filePath, TestableFile testableFile) + { + FilePath = filePath; + TestableFile = testableFile; + } + } + + internal enum BasicRuntimeOption + { + Include, + Exclude, + Embed, + + // Consumer manually controls the vb runtime via the provided arguments + Manual, + } + + /// + /// Provides an easy to test version of . This uses + /// to abstract way all of the file system access (typically the hardest part about testing CommonCompiler). + /// + internal sealed class TestableCompiler + { + internal static string RootDirectory => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"q:\" : "/"; + internal static BuildPaths StandardBuildPaths => new BuildPaths( + clientDir: Path.Combine(RootDirectory, "compiler"), + workingDir: Path.Combine(RootDirectory, "source"), + sdkDir: Path.Combine(RootDirectory, "sdk"), + tempDir: null); + + internal CommonCompiler Compiler { get; } + internal TestableFileSystem FileSystem { get; } + internal BuildPaths BuildPaths { get; } + + internal TestableCompiler(CommonCompiler compiler, TestableFileSystem fileSystem, BuildPaths buildPaths) + { + if (!object.ReferenceEquals(compiler.FileSystem, fileSystem)) + { + throw new ArgumentException(null, nameof(fileSystem)); + } + + Compiler = compiler; + FileSystem = fileSystem; + BuildPaths = buildPaths; + } + + internal (int Result, string Output) Run(CancellationToken cancellationToken = default) + => Compiler.Run(cancellationToken); + + internal TestableCompilerFile AddSourceFile(string filePath, string content) + { + var file = new TestableFile(content); + filePath = Path.Combine(BuildPaths.WorkingDirectory, filePath); + FileSystem.Map.Add(filePath, file); + return new TestableCompilerFile(filePath, file); + } + + internal TestableCompilerFile AddReference(string filePath, byte[] imageBytes) + { + var file = new TestableFile(imageBytes); + filePath = Path.Combine(BuildPaths.SdkDirectory!, filePath); + FileSystem.Map.Add(filePath, file); + return new TestableCompilerFile(filePath, file); + } + + internal TestableCompilerFile AddOutputFile(string filePath) + { + var file = new TestableFile(); + filePath = Path.Combine(BuildPaths.WorkingDirectory, filePath); + FileSystem.Map.Add(filePath, file); + return new TestableCompilerFile(filePath, file); + } + + internal static TestableCompiler CreateCSharp( + string[] commandLineArguments, + TestableFileSystem fileSystem, + BuildPaths? buildPaths = null) + { + var p = buildPaths ?? StandardBuildPaths; + var compiler = new CSharpCompilerImpl(commandLineArguments, p, fileSystem); + return new TestableCompiler(compiler, fileSystem, p); + } + + internal static TestableCompiler CreateCSharpNetCoreApp( + TestableFileSystem? fileSystem, + BuildPaths buildPaths, + IEnumerable commandLineArguments) + { + if (buildPaths.SdkDirectory is null) + { + throw new ArgumentException(null, nameof(buildPaths)); + } + + fileSystem ??= TestableFileSystem.CreateForMap(); + var args = new List(); + AppendNetCoreApp(fileSystem, buildPaths.SdkDirectory!, args, includeVisualBasicRuntime: false); + args.AddRange(commandLineArguments); + + var compiler = new CSharpCompilerImpl(args.ToArray(), buildPaths, fileSystem); + return new TestableCompiler(compiler, fileSystem, buildPaths); + } + + internal static TestableCompiler CreateCSharpNetCoreApp( + TestableFileSystem? fileSystem, + BuildPaths buildPaths, + params string[] commandLineArguments) + => CreateCSharpNetCoreApp(fileSystem, buildPaths, (IEnumerable)commandLineArguments); + + internal static TestableCompiler CreateCSharpNetCoreApp(params string[] commandLineArguments) + => CreateCSharpNetCoreApp(null, StandardBuildPaths, commandLineArguments); + + private sealed class CSharpCompilerImpl : CSharpCompiler + { + internal CSharpCompilerImpl(string[] args, BuildPaths buildPaths, TestableFileSystem? fileSystem) + : base(CSharpCommandLineParser.Default, responseFile: null, args, buildPaths, additionalReferenceDirectories: null, new DefaultAnalyzerAssemblyLoader(), fileSystem: fileSystem) + { + } + } + + internal static TestableCompiler CreateBasic( + string[] commandLineArguments, + TestableFileSystem fileSystem, + BuildPaths? buildPaths = null) + { + var p = buildPaths ?? StandardBuildPaths; + var compiler = new BasicCompilerImpl(commandLineArguments, p, fileSystem); + return new TestableCompiler(compiler, fileSystem, p); + } + + internal static TestableCompiler CreateBasicNetCoreApp( + TestableFileSystem? fileSystem, + BuildPaths buildPaths, + BasicRuntimeOption basicRuntimeOption, + IEnumerable commandLineArguments) + { + if (buildPaths.SdkDirectory is null) + { + throw new ArgumentException(null, nameof(buildPaths)); + } + + fileSystem ??= TestableFileSystem.CreateForMap(); + var args = new List(); + args.Add("-nostdlib"); + + switch (basicRuntimeOption) + { + case BasicRuntimeOption.Include: + // VB will just find this in the SDK path and auto-add it + args.Add($@"-vbruntime:""{Path.Combine(buildPaths.SdkDirectory, "Microsoft.VisualBasic.dll")}"""); + break; + case BasicRuntimeOption.Exclude: + args.Add("-vbruntime-"); + break; + case BasicRuntimeOption.Embed: + args.Add("-vbruntime+"); + break; + case BasicRuntimeOption.Manual: + break; + default: + throw new Exception("invalid value"); + } + + AppendNetCoreApp(fileSystem, buildPaths.SdkDirectory!, args, includeVisualBasicRuntime: false); + args.AddRange(commandLineArguments); + + var compiler = new BasicCompilerImpl(args.ToArray(), buildPaths, fileSystem); + return new TestableCompiler(compiler, fileSystem, buildPaths); + } + + internal static TestableCompiler CreateBasicNetCoreApp( + TestableFileSystem? fileSystem, + BuildPaths buildPaths, + params string[] commandLineArguments) + => CreateBasicNetCoreApp(fileSystem, buildPaths, BasicRuntimeOption.Include, (IEnumerable)commandLineArguments); + + internal static TestableCompiler CreateBasicNetCoreApp(params string[] commandLineArguments) + => CreateBasicNetCoreApp(null, StandardBuildPaths, BasicRuntimeOption.Include, commandLineArguments); + + private sealed class BasicCompilerImpl : VisualBasicCompiler + { + internal BasicCompilerImpl(string[] args, BuildPaths buildPaths, TestableFileSystem? fileSystem) + : base(VisualBasicCommandLineParser.Default, responseFile: null, args, buildPaths, additionalReferenceDirectories: null, new DefaultAnalyzerAssemblyLoader(), fileSystem: fileSystem) + { + } + } + + private static void AppendNetCoreApp(TestableFileSystem fileSystem, string sdkPath, List commandLineArgs, bool includeVisualBasicRuntime) + { + Debug.Assert(fileSystem.UsingMap); + foreach (var referenceInfo in NetCoreApp.AllReferenceInfos) + { + fileSystem.Map[Path.Combine(sdkPath, referenceInfo.FileName)] = new TestableFile(referenceInfo.ImageBytes); + + // The command line needs to make a decision about how to embed the VB runtime + if (!(!includeVisualBasicRuntime && referenceInfo.FileName == "Microsoft.VisualBasic.dll")) + { + commandLineArgs.Add($@"/reference:{referenceInfo.FileName}"); + } + } + } + } +} diff --git a/src/Compilers/Test/Core/TestableFileSystem.cs b/src/Compilers/Test/Core/TestableFileSystem.cs index b0b644d9f11d4..f3b129a7c7f36 100644 --- a/src/Compilers/Test/Core/TestableFileSystem.cs +++ b/src/Compilers/Test/Core/TestableFileSystem.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Roslyn.Utilities; namespace Roslyn.Test.Utilities @@ -14,9 +15,19 @@ namespace Roslyn.Test.Utilities public sealed class TestableFileSystem : ICommonCompilerFileSystem { - public OpenFileFunc OpenFileFunc { get; set; } = delegate { throw new InvalidOperationException(); }; - public OpenFileExFunc OpenFileExFunc { get; set; } = (string _, FileMode _, FileAccess _, FileShare _, int _, FileOptions _, out string _) => throw new InvalidOperationException(); - public Func FileExistsFunc { get; set; } = delegate { throw new InvalidOperationException(); }; + private readonly Dictionary? _map; + + public OpenFileFunc OpenFileFunc { get; private set; } = delegate { throw new InvalidOperationException(); }; + public OpenFileExFunc OpenFileExFunc { get; private set; } = (string _, FileMode _, FileAccess _, FileShare _, int _, FileOptions _, out string _) => throw new InvalidOperationException(); + public Func FileExistsFunc { get; private set; } = delegate { throw new InvalidOperationException(); }; + + public Dictionary Map => _map ?? throw new InvalidOperationException(); + public bool UsingMap => _map is not null; + + private TestableFileSystem(Dictionary? map = null) + { + _map = map; + } public Stream OpenFile(string filePath, FileMode mode, FileAccess access, FileShare share) => OpenFileFunc(filePath, mode, access, share); @@ -50,8 +61,18 @@ public static TestableFileSystem CreateForExistingPaths(IEnumerable exis }; } + public static TestableFileSystem CreateForFiles(params (string FilePath, TestableFile TestableFile)[] files) + { + var map = files.ToDictionary( + x => x.FilePath, + x => x.TestableFile); + return CreateForMap(map); + } + + public static TestableFileSystem CreateForMap() => CreateForMap(new()); + public static TestableFileSystem CreateForMap(Dictionary map) - => new TestableFileSystem() + => new TestableFileSystem(map) { OpenFileExFunc = (string filePath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, out string normalizedFilePath) => { diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs index 66a26418fe87d..942c762f2247a 100644 --- a/src/Compilers/Test/Core/Traits/Traits.cs +++ b/src/Compilers/Test/Core/Traits/Traits.cs @@ -74,6 +74,7 @@ public static class Features public const string CodeActionsConvertLocalFunctionToMethod = "CodeActions.ConvertLocalFunctionToMethod"; public const string CodeActionsConvertNumericLiteral = "CodeActions.ConvertNumericLiteral"; public const string CodeActionsConvertQueryToForEach = "CodeActions.ConvertQueryToForEach"; + public const string CodeActionsConvertRegularToRawString = "CodeActions.CodeActionsConvertRegularToRawString"; public const string CodeActionsConvertSwitchStatementToExpression = "CodeActions.ConvertSwitchStatementToExpression"; public const string CodeActionsConvertToInterpolatedString = "CodeActions.ConvertToInterpolatedString"; public const string CodeActionsConvertToIterator = "CodeActions.ConvertToIterator"; @@ -82,6 +83,7 @@ public static class Features public const string CodeActionsCorrectFunctionReturnType = "CodeActions.CorrectFunctionReturnType"; public const string CodeActionsCorrectNextControlVariable = "CodeActions.CorrectNextControlVariable"; public const string CodeActionsDeclareAsNullable = "CodeActions.DeclareAsNullable"; + public const string CodeActionsDetectJsonString = "CodeActions.DetectJsonString"; public const string CodeActionsExtractInterface = "CodeActions.ExtractInterface"; public const string CodeActionsExtractLocalFunction = "CodeActions.ExtractLocalFunction"; public const string CodeActionsExtractMethod = "CodeActions.ExtractMethod"; @@ -118,7 +120,7 @@ public static class Features public const string CodeActionsInvertIf = "CodeActions.InvertIf"; public const string CodeActionsInvertLogical = "CodeActions.InvertLogical"; public const string CodeActionsInvokeDelegateWithConditionalAccess = "CodeActions.InvokeDelegateWithConditionalAccess"; - public const string CodeActionsLambdaSimplifier = "CodeActions.LambdaSimplifier"; + public const string CodeActionsRemoveUnnecessaryLambdaExpression = "CodeActions.RemoveUnnecessaryLambdaExpression"; public const string CodeActionsMakeFieldReadonly = "CodeActions.MakeFieldReadonly"; public const string CodeActionsMakeLocalFunctionStatic = "CodeActions.MakeLocalFunctionStatic"; public const string CodeActionsMakeMethodAsynchronous = "CodeActions.MakeMethodAsynchronous"; @@ -194,6 +196,7 @@ public static class Features public const string CodeActionsUseInterpolatedVerbatimString = "CodeActions.UseInterpolatedVerbatimString"; public const string CodeActionsUseIsNotExpression = "CodeActions.UseIsNotExpression"; public const string CodeActionsUseIsNullCheck = "CodeActions.UseIsNullCheck"; + public const string CodeActionsUseParameterNullChecking = "CodeActions.UseParameterNullChecking"; public const string CodeActionsUseLocalFunction = "CodeActions.UseLocalFunction"; public const string CodeActionsUseNamedArguments = "CodeActions.UseNamedArguments"; public const string CodeActionsUseNotPattern = "CodeActions.UseNotPattern"; @@ -295,6 +298,7 @@ public static class Features public const string SourceGenerators = nameof(SourceGenerators); public const string SplitComment = nameof(SplitComment); public const string SplitStringLiteral = nameof(SplitStringLiteral); + public const string StringIndentation = nameof(StringIndentation); public const string SuggestionTags = nameof(SuggestionTags); public const string SyncNamespaces = nameof(SyncNamespaces); public const string TargetTypedCompletion = nameof(TargetTypedCompletion); @@ -305,6 +309,7 @@ public static class Features public const string TypeInferenceService = nameof(TypeInferenceService); public const string UnusedReferences = nameof(UnusedReferences); public const string ValidateFormatString = nameof(ValidateFormatString); + public const string ValidateJsonString = nameof(ValidateJsonString); public const string ValidateRegexString = nameof(ValidateRegexString); public const string Venus = nameof(Venus); public const string VsLanguageBlock = nameof(VsLanguageBlock); diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index ef99a145bc866..7ec96c09388a9 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -269,20 +269,38 @@ public AsyncIteratorStateMachineAttribute(Type stateMachineType) : base(stateMac namespace System.Threading.Tasks.Sources { + // From https://github.com/dotnet/runtime/blob/f580068aa93fb3c6d5fbc7e33f6cd7d52fa86b24/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs using System.Diagnostics; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; + /// Provides the core logic for implementing a manual-reset or . + /// [StructLayout(LayoutKind.Auto)] public struct ManualResetValueTaskSourceCore { + /// + /// The callback to invoke when the operation completes if was called before the operation completed, + /// or if the operation completed before a callback was supplied, + /// or null if a callback hasn't yet been provided and the operation hasn't yet completed. + /// private Action _continuation; + /// State to pass to . private object _continuationState; + /// to flow to the callback, or null if no flowing is required. private ExecutionContext _executionContext; + /// + /// A ""captured"" or with which to invoke the callback, + /// or null if no special context is required. + /// private object _capturedContext; + /// Whether the current operation has completed. private bool _completed; + /// The result with which the operation succeeded, or the default value if it hasn't yet completed or failed. private TResult _result; + /// The exception with which the operation failed, or null if it hasn't yet completed or completed successfully. private ExceptionDispatchInfo _error; + /// The current version of this value, used to help prevent misuse. private short _version; /// Gets or sets whether to force continuations to run asynchronously. @@ -303,42 +321,56 @@ public void Reset() _continuationState = null; } + /// Completes with a successful result. + /// The result. public void SetResult(TResult result) { _result = result; SignalCompletion(); } + /// Complets with an error. + /// public void SetException(Exception error) { _error = ExceptionDispatchInfo.Capture(error); SignalCompletion(); } + /// Gets the operation version. public short Version => _version; + /// Gets the status of the operation. + /// Opaque value that was provided to the 's constructor. public ValueTaskSourceStatus GetStatus(short token) { ValidateToken(token); return - !_completed ? ValueTaskSourceStatus.Pending : + _continuation == null || !_completed ? ValueTaskSourceStatus.Pending : _error == null ? ValueTaskSourceStatus.Succeeded : _error.SourceException is OperationCanceledException ? ValueTaskSourceStatus.Canceled : ValueTaskSourceStatus.Faulted; } + /// Gets the result of the operation. + /// Opaque value that was provided to the 's constructor. public TResult GetResult(short token) { ValidateToken(token); if (!_completed) { - ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException(); + throw new InvalidOperationException(); } _error?.Throw(); return _result; } + /// Schedules the continuation action for this operation. + /// The continuation to invoke when the operation has completed. + /// The state object to pass to when it's invoked. + /// Opaque value that was provided to the 's constructor. + /// The flags describing the behavior of the continuation. public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { if (continuation == null) @@ -389,7 +421,7 @@ public void OnCompleted(Action continuation, object state, short token, // Operation already completed, so we need to queue the supplied callback. if (!ReferenceEquals(oldContinuation, ManualResetValueTaskSourceCoreShared.s_sentinel)) { - ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException(); + throw new InvalidOperationException(); } switch (_capturedContext) @@ -413,19 +445,22 @@ public void OnCompleted(Action continuation, object state, short token, } } + /// Ensures that the specified token matches the current version. + /// The token supplied by . private void ValidateToken(short token) { if (token != _version) { - ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException(); + throw new InvalidOperationException(); } } + /// Signals that the operation has completed. Invoked after the result or error has been set. private void SignalCompletion() { if (_completed) { - ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException(); + throw new InvalidOperationException(); } _completed = true; @@ -445,8 +480,15 @@ private void SignalCompletion() } } + /// + /// Invokes the continuation with the appropriate captured context / scheduler. + /// This assumes that if is not null we're already + /// running within that . + /// private void InvokeContinuation() { + Debug.Assert(_continuation != null); + switch (_capturedContext) { case null: @@ -477,13 +519,14 @@ private void InvokeContinuation() internal static class ManualResetValueTaskSourceCoreShared // separated out of generic to avoid unnecessary duplication { - internal static void ThrowInvalidOperationException() => throw new InvalidOperationException(); - internal static readonly Action s_sentinel = CompletionSentinel; private static void CompletionSentinel(object _) // named method to aid debugging { + // Instrumented with FailFast to investigate CI failure: + // https://github.com/dotnet/roslyn/issues/34207 + System.Environment.FailFast(""The sentinel delegate should never be invoked.""); Debug.Fail(""The sentinel delegate should never be invoked.""); - ThrowInvalidOperationException(); + throw new InvalidOperationException(); } } } @@ -612,6 +655,7 @@ internal CompilationVerifier CompileAndVerifyWithMscorlib40( Action symbolValidator = null, SignatureDescription[] expectedSignatures = null, string expectedOutput = null, + bool trimOutput = true, int? expectedReturnCode = null, string[] args = null, CSharpCompilationOptions options = null, @@ -628,6 +672,7 @@ internal CompilationVerifier CompileAndVerifyWithMscorlib40( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -646,6 +691,7 @@ internal CompilationVerifier CompileAndVerifyWithMscorlib46( Action symbolValidator = null, SignatureDescription[] expectedSignatures = null, string expectedOutput = null, + bool trimOutput = true, int? expectedReturnCode = null, string[] args = null, CSharpCompilationOptions options = null, @@ -662,6 +708,7 @@ internal CompilationVerifier CompileAndVerifyWithMscorlib46( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -681,6 +728,7 @@ internal CompilationVerifier CompileAndVerifyExperimental( Action symbolValidator = null, SignatureDescription[] expectedSignatures = null, string expectedOutput = null, + bool trimOutput = true, int? expectedReturnCode = null, string[] args = null, CSharpCompilationOptions options = null, @@ -701,6 +749,7 @@ internal CompilationVerifier CompileAndVerifyExperimental( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -720,6 +769,7 @@ internal CompilationVerifier CompileAndVerifyWithWinRt( Action symbolValidator = null, SignatureDescription[] expectedSignatures = null, string expectedOutput = null, + bool trimOutput = true, int? expectedReturnCode = null, string[] args = null, CSharpCompilationOptions options = null, @@ -736,6 +786,7 @@ internal CompilationVerifier CompileAndVerifyWithWinRt( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -754,6 +805,7 @@ internal CompilationVerifier CompileAndVerifyWithCSharp( Action symbolValidator = null, SignatureDescription[] expectedSignatures = null, string expectedOutput = null, + bool trimOutput = true, int? expectedReturnCode = null, string[] args = null, CSharpCompilationOptions options = null, @@ -770,6 +822,7 @@ internal CompilationVerifier CompileAndVerifyWithCSharp( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -788,6 +841,7 @@ internal CompilationVerifier CompileAndVerify( Action symbolValidator = null, SignatureDescription[] expectedSignatures = null, string expectedOutput = null, + bool trimOutput = true, int? expectedReturnCode = null, string[] args = null, CSharpCompilationOptions options = null, @@ -807,6 +861,7 @@ internal CompilationVerifier CompileAndVerify( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, emitOptions, @@ -822,6 +877,7 @@ internal CompilationVerifier CompileAndVerify( Action symbolValidator = null, SignatureDescription[] expectedSignatures = null, string expectedOutput = null, + bool trimOutput = true, int? expectedReturnCode = null, string[] args = null, EmitOptions emitOptions = null, @@ -848,6 +904,7 @@ Action translate(Action action) translate(symbolValidator), expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, emitOptions, @@ -872,14 +929,14 @@ internal CompilationVerifier CompileAndVerifyFieldMarshal(CSharpTestSource sourc #region SyntaxTree Factories - public static SyntaxTree Parse(string text, string filename = "", CSharpParseOptions options = null, Encoding encoding = null) + public static SyntaxTree Parse(string text, string filename = "", CSharpParseOptions options = null, Encoding encoding = null, SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithm.Sha1) { if ((object)options == null) { options = TestOptions.RegularPreview; } - var stringText = StringText.From(text, encoding ?? Encoding.UTF8); + var stringText = StringText.From(text, encoding ?? Encoding.UTF8, checksumAlgorithm); return CheckSerializable(SyntaxFactory.ParseSyntaxTree(stringText, options, filename)); } @@ -1397,6 +1454,12 @@ protected static TNode GetSyntaxNodeOfTypeForBinding(List syn string exprFullText = node.ToFullString(); exprFullText = exprFullText.Trim(); + // Account for comments being added as leading trivia for this node. + while (exprFullText.StartsWith("//")) + { + exprFullText = exprFullText[exprFullText.IndexOf('\n')..].Trim(); + } + if (exprFullText.StartsWith(StartString, StringComparison.Ordinal)) { if (exprFullText.Contains(EndString)) diff --git a/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb b/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb index c987e4fc48e5c..206f8a3427334 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/BasicTestBase.vb @@ -27,6 +27,7 @@ Public MustInherit Class BasicTestBase Friend Shadows Function CompileAndVerify( source As XElement, expectedOutput As XCData, + Optional trimOutput As Boolean = True, Optional expectedReturnCode As Integer? = Nothing, Optional args As String() = Nothing, Optional references As MetadataReference() = Nothing, @@ -44,6 +45,7 @@ Public MustInherit Class BasicTestBase Return CompileAndVerify( source, XCDataToString(expectedOutput), + trimOutput, expectedReturnCode, args, references, @@ -67,6 +69,7 @@ Public MustInherit Class BasicTestBase Optional symbolValidator As Action(Of ModuleSymbol) = Nothing, Optional expectedSignatures As SignatureDescription() = Nothing, Optional expectedOutput As String = Nothing, + Optional trimOutput As Boolean = True, Optional expectedReturnCode As Integer? = Nothing, Optional args As String() = Nothing, Optional emitOptions As EmitOptions = Nothing, @@ -81,6 +84,7 @@ Public MustInherit Class BasicTestBase Translate(symbolValidator), expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, emitOptions, @@ -90,6 +94,7 @@ Public MustInherit Class BasicTestBase Friend Shadows Function CompileAndVerify( compilation As Compilation, expectedOutput As XCData, + Optional trimOutput As Boolean = True, Optional args As String() = Nothing, Optional manifestResources As IEnumerable(Of ResourceDescription) = Nothing, Optional dependencies As IEnumerable(Of ModuleData) = Nothing, @@ -109,6 +114,7 @@ Public MustInherit Class BasicTestBase symbolValidator, expectedSignatures, XCDataToString(expectedOutput), + trimOutput, Nothing, args, emitOptions, @@ -118,6 +124,7 @@ Public MustInherit Class BasicTestBase Friend Shadows Function CompileAndVerify( source As XElement, Optional expectedOutput As String = Nothing, + Optional trimOutput As Boolean = True, Optional expectedReturnCode As Integer? = Nothing, Optional args As String() = Nothing, Optional references As MetadataReference() = Nothing, @@ -139,6 +146,7 @@ Public MustInherit Class BasicTestBase Return Me.CompileAndVerify(source, allReferences, expectedOutput, + trimOutput, expectedReturnCode, args, dependencies, @@ -157,6 +165,7 @@ Public MustInherit Class BasicTestBase source As XElement, allReferences As IEnumerable(Of MetadataReference), Optional expectedOutput As String = Nothing, + Optional trimOutput As Boolean = True, Optional expectedReturnCode As Integer? = Nothing, Optional args As String() = Nothing, Optional dependencies As IEnumerable(Of ModuleData) = Nothing, @@ -187,6 +196,7 @@ Public MustInherit Class BasicTestBase Translate(symbolValidator), expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, emitOptions, @@ -197,6 +207,7 @@ Public MustInherit Class BasicTestBase source As XElement, allReferences As IEnumerable(Of MetadataReference), Optional expectedOutput As String = Nothing, + Optional trimOutput As Boolean = True, Optional expectedReturnCode As Integer? = Nothing, Optional args As String() = Nothing, Optional dependencies As IEnumerable(Of ModuleData) = Nothing, @@ -212,6 +223,7 @@ Public MustInherit Class BasicTestBase source, allReferences, If(OSVersion.IsWin8, expectedOutput, Nothing), + trimOutput, If(OSVersion.IsWin8, expectedReturnCode, Nothing), args, dependencies, @@ -227,6 +239,7 @@ Public MustInherit Class BasicTestBase Friend Shadows Function CompileAndVerifyOnWin8Only( source As XElement, expectedOutput As XCData, + Optional trimOutput As Boolean = True, Optional expectedReturnCode As Integer? = Nothing, Optional args As String() = Nothing, Optional allReferences() As MetadataReference = Nothing, @@ -243,6 +256,7 @@ Public MustInherit Class BasicTestBase source, allReferences, XCDataToString(expectedOutput), + trimOutput, expectedReturnCode, args, dependencies, @@ -288,6 +302,7 @@ Public MustInherit Class BasicTestBase source As BasicTestSource, Optional references As IEnumerable(Of MetadataReference) = Nothing, Optional expectedOutput As String = Nothing, + Optional trimOutput As Boolean = True, Optional expectedReturnCode As Integer? = Nothing, Optional args As String() = Nothing, Optional dependencies As IEnumerable(Of ModuleData) = Nothing, @@ -317,6 +332,7 @@ Public MustInherit Class BasicTestBase Translate(symbolValidator), expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, emitOptions, diff --git a/src/Compilers/Test/Utilities/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.Test.Utilities.vbproj b/src/Compilers/Test/Utilities/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.Test.Utilities.vbproj index d2676fbd32089..ce86643dcc5ac 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.Test.Utilities.vbproj +++ b/src/Compilers/Test/Utilities/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.Test.Utilities.vbproj @@ -37,6 +37,7 @@ + diff --git a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCompiler.vb b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCompiler.vb index ecc22ddc8860e..20beca8130ae1 100644 --- a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCompiler.vb @@ -22,8 +22,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Private ReadOnly _tempDirectory As String Private _additionalTextFiles As ImmutableArray(Of AdditionalTextFile) - Protected Sub New(parser As VisualBasicCommandLineParser, responseFile As String, args As String(), buildPaths As BuildPaths, additionalReferenceDirectories As String, analyzerLoader As IAnalyzerAssemblyLoader, Optional driverCache As GeneratorDriverCache = Nothing) - MyBase.New(parser, responseFile, args, buildPaths, additionalReferenceDirectories, analyzerLoader, driverCache) + Protected Sub New(parser As VisualBasicCommandLineParser, responseFile As String, args As String(), buildPaths As BuildPaths, additionalReferenceDirectories As String, analyzerLoader As IAnalyzerAssemblyLoader, Optional driverCache As GeneratorDriverCache = Nothing, Optional fileSystem As ICommonCompilerFileSystem = Nothing) + MyBase.New(parser, responseFile, args, buildPaths, additionalReferenceDirectories, analyzerLoader, driverCache, fileSystem) _diagnosticFormatter = New CommandLineDiagnosticFormatter(buildPaths.WorkingDirectory, AddressOf GetAdditionalTextFiles) _additionalTextFiles = Nothing diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb index f600e10b64cd3..2f8a3cd02943f 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb @@ -2503,15 +2503,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return True End Function - Friend Overrides Function GenerateResourcesAndDocumentationComments( + Friend Overrides Function GenerateResources( moduleBuilder As CommonPEModuleBuilder, - xmlDocStream As Stream, win32Resources As Stream, useRawWin32Resources As Boolean, - outputNameOverride As String, diagnostics As DiagnosticBag, cancellationToken As CancellationToken) As Boolean + cancellationToken.ThrowIfCancellationRequested() + ' Use a temporary bag so we don't have to refilter pre-existing diagnostics. Dim resourceDiagnostics = DiagnosticBag.GetInstance() @@ -2524,9 +2524,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic AddedModulesResourceNames(resourceDiagnostics), resourceDiagnostics) - If Not FilterAndAppendAndFreeDiagnostics(diagnostics, resourceDiagnostics, cancellationToken) Then - Return False - End If + Return FilterAndAppendAndFreeDiagnostics(diagnostics, resourceDiagnostics, cancellationToken) + End Function + + Friend Overrides Function GenerateDocumentationComments( + xmlDocStream As Stream, + outputNameOverride As String, + diagnostics As DiagnosticBag, + cancellationToken As CancellationToken) As Boolean cancellationToken.ThrowIfCancellationRequested() diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicDeterministicKeyBuilder.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicDeterministicKeyBuilder.vb new file mode 100644 index 0000000000000..0bcd25b419f35 --- /dev/null +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicDeterministicKeyBuilder.vb @@ -0,0 +1,99 @@ +' Licensed to the .NET Foundation under one or more 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.Globalization + +Namespace Microsoft.CodeAnalysis.VisualBasic + + Friend NotInheritable Class VisualBasicDeterministicKeyBuilder + Inherits DeterministicKeyBuilder + + Friend Shared ReadOnly Instance As New VisualBasicDeterministicKeyBuilder() + + Private Sub New() + + End Sub + + Protected Overrides Sub WriteParseOptionsCore(writer As JsonWriter, parseOptions As ParseOptions) + + ' This can happen for SyntaxTree that are constructed via the API. + If parseOptions Is Nothing Then + Return + End If + + Dim basicOptions = TryCast(parseOptions, VisualBasicParseOptions) + If basicOptions Is Nothing Then + Throw New InvalidOperationException() + End If + + MyBase.WriteParseOptionsCore(writer, parseOptions) + + writer.Write("languageVersion", basicOptions.LanguageVersion) + writer.Write("specifiedLanguageVersion", basicOptions.SpecifiedLanguageVersion) + + writer.WriteKey("preprocessorSymbols") + writer.WriteObjectStart() + For Each pair In basicOptions.PreprocessorSymbols.OrderBy(Function(x, y) StringComparer.Ordinal.Compare(x.Key, y.Key)) + Dim value = pair.Value + If value Is Nothing Then + writer.WriteNull(pair.Key) + Continue For + End If + + writer.WriteKey(pair.Key) + + Dim type = value.GetType() + If type = GetType(String) Then + writer.Write(CType(value, String)) + ElseIf type = GetType(Boolean) Then + writer.Write(CType(value, Boolean)) + Else + Dim formattable = TryCast(value, IFormattable) + If formattable IsNot Nothing Then + writer.Write(formattable.ToString(Nothing, CultureInfo.InvariantCulture)) + Else + Throw ExceptionUtilities.UnexpectedValue(value) + End If + End If + Next + writer.WriteObjectEnd() + + End Sub + + Protected Overrides Sub WriteCompilationOptionsCore(writer As JsonWriter, options As CompilationOptions) + Dim basicOptions = TryCast(options, VisualBasicCompilationOptions) + If basicOptions Is Nothing Then + Throw New InvalidOperationException() + End If + + MyBase.WriteCompilationOptionsCore(writer, options) + + writer.Write("rootNamespace", basicOptions.RootNamespace) + writer.Write("optionStrict", basicOptions.OptionStrict) + writer.Write("optionInfer", basicOptions.OptionInfer) + writer.Write("optionExplicit", basicOptions.OptionExplicit) + writer.Write("optionCompareText", basicOptions.OptionCompareText) + writer.Write("embedVbCoreRuntime", basicOptions.EmbedVbCoreRuntime) + + writer.WriteKey("globalImports") + writer.WriteArrayStart() + For Each import In basicOptions.GlobalImports + writer.WriteObjectStart() + writer.Write("name", import.Name) + writer.Write("isXmlClause", import.IsXmlClause) + writer.WriteObjectEnd() + Next + writer.WriteArrayEnd() + + writer.WriteKey("parseOptions") + If basicOptions.ParseOptions IsNot Nothing Then + WriteParseOptions(writer, basicOptions.ParseOptions) + Else + writer.WriteNull() + End If + End Sub + + End Class + +End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb index 1954808a25714..ca213c02940cc 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb @@ -115,9 +115,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Dim metadataAssembly = metadataCompilation.GetBoundReferenceManager().CreatePEAssemblyForAssemblyMetadata(AssemblyMetadata.Create(originalMetadata), MetadataImportOptions.All, assemblyReferenceIdentityMap) Dim metadataDecoder = New MetadataDecoder(metadataAssembly.PrimaryModule) Dim metadataAnonymousTypes = GetAnonymousTypeMapFromMetadata(originalMetadata.MetadataReader, metadataDecoder) - ' VB synthesized delegates are handled as anonymous types in the map above - Dim synthesizedDelegates = SpecializedCollections.EmptyReadOnlyDictionary(Of SynthesizedDelegateKey, SynthesizedDelegateValue) - Dim metadataSymbols = New EmitBaseline.MetadataSymbols(metadataAnonymousTypes, synthesizedDelegates, metadataDecoder, assemblyReferenceIdentityMap) + ' VB anonymous delegates are handled as anonymous types in the map above + Dim anonymousDelegates = SpecializedCollections.EmptyReadOnlyDictionary(Of SynthesizedDelegateKey, SynthesizedDelegateValue) + Dim anonymousDelegatesWithFixedTypes = SpecializedCollections.EmptyReadOnlyDictionary(Of String, AnonymousTypeValue) + Dim metadataSymbols = New EmitBaseline.MetadataSymbols(metadataAnonymousTypes, anonymousDelegates, anonymousDelegatesWithFixedTypes, metadataDecoder, assemblyReferenceIdentityMap) Return InterlockedOperations.Initialize(initialBaseline.LazyMetadataSymbols, metadataSymbols) End Function @@ -235,11 +236,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Return anonymousTypes End Function - Friend Overloads Function GetSynthesizedDelegates() As IReadOnlyDictionary(Of SynthesizedDelegateKey, SynthesizedDelegateValue) Implements IPEDeltaAssemblyBuilder.GetSynthesizedDelegates - ' VB synthesized delegates are handled as anonymous types in the method above + Friend Overloads Function GetAnonymousDelegates() As IReadOnlyDictionary(Of SynthesizedDelegateKey, SynthesizedDelegateValue) Implements IPEDeltaAssemblyBuilder.GetAnonymousDelegates + ' VB anonymous delegates are handled as anonymous types in the method above Return SpecializedCollections.EmptyReadOnlyDictionary(Of SynthesizedDelegateKey, SynthesizedDelegateValue) End Function + Friend Overloads Function GetAnonymousDelegatesWithFixedTypes() As IReadOnlyDictionary(Of String, AnonymousTypeValue) Implements IPEDeltaAssemblyBuilder.GetAnonymousDelegatesWithFixedTypes + ' VB anonymous delegates are handled as anonymous types in the method above + Return SpecializedCollections.EmptyReadOnlyDictionary(Of String, AnonymousTypeValue) + End Function + Friend Overrides Function TryCreateVariableSlotAllocator(method As MethodSymbol, topLevelMethod As MethodSymbol, diagnostics As DiagnosticBag) As VariableSlotAllocator Return _previousDefinitions.TryCreateVariableSlotAllocator(_previousGeneration, Compilation, method, topLevelMethod, diagnostics) End Function diff --git a/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.vb b/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.vb index fbf0a7371c11c..874a2322c203c 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.vb @@ -235,7 +235,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return RewriteReceiverArgumentsAndGenerateAccessorCall(node.Syntax, setMethod, setNode.ReceiverOpt, - setNode.Arguments.Concat(ImmutableArray.Create(node.Right)), + setNode.Arguments.Concat(node.Right), node.ConstantValueOpt, isLValue:=False, suppressObjectClone:=False, diff --git a/src/Compilers/VisualBasic/Portable/PublicAPI.Shipped.txt b/src/Compilers/VisualBasic/Portable/PublicAPI.Shipped.txt index 01e8bccb87741..0136b50c7311d 100644 --- a/src/Compilers/VisualBasic/Portable/PublicAPI.Shipped.txt +++ b/src/Compilers/VisualBasic/Portable/PublicAPI.Shipped.txt @@ -67,6 +67,7 @@ Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic15 = 15 -> Microso Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic15_3 = 1503 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic15_5 = 1505 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic16 = 1600 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion +Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic16_9 = 1609 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic9 = 9 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.LanguageVersionFacts Microsoft.CodeAnalysis.VisualBasic.LanguageVersionFacts.MapSpecifiedToEffectiveVersion(version As Microsoft.CodeAnalysis.VisualBasic.LanguageVersion) -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion @@ -3362,6 +3363,7 @@ Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.TryGetSpeculativeSemant Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.TryGetSpeculativeSemanticModel(semanticModel As Microsoft.CodeAnalysis.SemanticModel, position As Integer, statement As Microsoft.CodeAnalysis.VisualBasic.Syntax.ExecutableStatementSyntax, ByRef speculativeModel As Microsoft.CodeAnalysis.SemanticModel) -> Boolean Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.TryGetSpeculativeSemanticModel(semanticModel As Microsoft.CodeAnalysis.SemanticModel, position As Integer, type As Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeSyntax, ByRef speculativeModel As Microsoft.CodeAnalysis.SemanticModel, bindingOption As Microsoft.CodeAnalysis.SpeculativeBindingOption = Microsoft.CodeAnalysis.SpeculativeBindingOption.BindAsExpression) -> Boolean Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.TryGetSpeculativeSemanticModelForMethodBody(semanticModel As Microsoft.CodeAnalysis.SemanticModel, position As Integer, method As Microsoft.CodeAnalysis.VisualBasic.Syntax.MethodBlockBaseSyntax, ByRef speculativeModel As Microsoft.CodeAnalysis.SemanticModel) -> Boolean +Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions.LanguageVersion() -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions.New(languageVersion As Microsoft.CodeAnalysis.VisualBasic.LanguageVersion = Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.Default, documentationMode As Microsoft.CodeAnalysis.DocumentationMode = Microsoft.CodeAnalysis.DocumentationMode.Parse, kind As Microsoft.CodeAnalysis.SourceCodeKind = Microsoft.CodeAnalysis.SourceCodeKind.Regular, preprocessorSymbols As System.Collections.Generic.IEnumerable(Of System.Collections.Generic.KeyValuePair(Of String, Object)) = Nothing) -> Void @@ -4528,6 +4530,7 @@ Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.GetMethodBod Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.GetParseDiagnostics(cancellationToken As System.Threading.CancellationToken = Nothing) -> System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.Diagnostic) Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.GetSymbolsWithName(name As String, filter As Microsoft.CodeAnalysis.SymbolFilter = Microsoft.CodeAnalysis.SymbolFilter.TypeAndMember, cancellationToken As System.Threading.CancellationToken = Nothing) -> System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.ISymbol) Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.GetSymbolsWithName(predicate As System.Func(Of String, Boolean), filter As Microsoft.CodeAnalysis.SymbolFilter = Microsoft.CodeAnalysis.SymbolFilter.TypeAndMember, cancellationToken As System.Threading.CancellationToken = Nothing) -> System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.ISymbol) +Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.GetUsedAssemblyReferences(cancellationToken As System.Threading.CancellationToken = Nothing) -> System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.MetadataReference) Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.IsCaseSensitive() -> Boolean Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.Language() -> String Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.ReferencedAssemblyNames() -> System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.AssemblyIdentity) @@ -4795,6 +4798,7 @@ Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.GetDiagnostic Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.GetDiagnostics(nodeOrToken As Microsoft.CodeAnalysis.SyntaxNodeOrToken) -> System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.Diagnostic) Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.GetDiagnostics(token As Microsoft.CodeAnalysis.SyntaxToken) -> System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.Diagnostic) Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.GetDiagnostics(trivia As Microsoft.CodeAnalysis.SyntaxTrivia) -> System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.Diagnostic) +Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.GetLineMappings(cancellationToken As System.Threading.CancellationToken = Nothing) -> System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.LineMapping) Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.GetLineSpan(span As Microsoft.CodeAnalysis.Text.TextSpan, cancellationToken As System.Threading.CancellationToken = Nothing) -> Microsoft.CodeAnalysis.FileLinePositionSpan Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.GetLineVisibility(position As Integer, cancellationToken As System.Threading.CancellationToken = Nothing) -> Microsoft.CodeAnalysis.LineVisibility Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.GetLocation(span As Microsoft.CodeAnalysis.Text.TextSpan) -> Microsoft.CodeAnalysis.Location @@ -6079,6 +6083,8 @@ Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicCommandLineParser.ParseCond Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicCommandLineParser.Script() -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicCommandLineParser Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.Create(assemblyName As String, syntaxTrees As System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.SyntaxTree) = Nothing, references As System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.MetadataReference) = Nothing, options As Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilationOptions = Nothing) -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicDiagnosticFormatter.Instance() -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicDiagnosticFormatter +Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver.Create(generators As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.ISourceGenerator), additionalTexts As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.AdditionalText) = Nothing, parseOptions As Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions = Nothing, analyzerConfigOptionsProvider As Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider = Nothing, driverOptions As Microsoft.CodeAnalysis.GeneratorDriverOptions = Nothing) -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver +Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver.Create(generators As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.ISourceGenerator), additionalTexts As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.AdditionalText), parseOptions As Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions, analyzerConfigOptionsProvider As Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider) -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions.Default() -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode.DeserializeFrom(stream As System.IO.Stream, cancellationToken As System.Threading.CancellationToken = Nothing) -> Microsoft.CodeAnalysis.SyntaxNode Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.Create(root As Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode, options As Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions = Nothing, path As String = "", encoding As System.Text.Encoding = Nothing, diagnosticOptions As System.Collections.Immutable.ImmutableDictionary(Of String, Microsoft.CodeAnalysis.ReportDiagnostic) = Nothing) -> Microsoft.CodeAnalysis.SyntaxTree diff --git a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt index 73dda7aa39f94..8b137891791fe 100644 --- a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt @@ -1,7 +1 @@ -Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic16_9 = 1609 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion -Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver -Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree.GetLineMappings(cancellationToken As System.Threading.CancellationToken = Nothing) -> System.Collections.Generic.IEnumerable(Of Microsoft.CodeAnalysis.LineMapping) -Overrides Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.GetUsedAssemblyReferences(cancellationToken As System.Threading.CancellationToken = Nothing) -> System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.MetadataReference) -*REMOVED*Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver.Create(generators As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.ISourceGenerator), additionalTexts As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.AdditionalText) = Nothing, parseOptions As Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions = Nothing, analyzerConfigOptionsProvider As Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider = Nothing) -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver -Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver.Create(generators As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.ISourceGenerator), additionalTexts As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.AdditionalText) = Nothing, parseOptions As Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions = Nothing, analyzerConfigOptionsProvider As Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider = Nothing, driverOptions As Microsoft.CodeAnalysis.GeneratorDriverOptions = Nothing) -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver -Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver.Create(generators As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.ISourceGenerator), additionalTexts As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.AdditionalText), parseOptions As Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions, analyzerConfigOptionsProvider As Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider) -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver \ No newline at end of file + diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb index 9104a8864e97f..9a726b552ca70 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb @@ -359,12 +359,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Private ReadOnly Property IsNullChecked As Boolean Implements IParameterSymbol.IsNullChecked - Get - Return False - End Get - End Property - Public Overrides Sub Accept(visitor As SymbolVisitor) visitor.VisitParameter(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb b/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb index 7492658a959ce..ff4d41831ce7b 100644 --- a/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb +++ b/src/Compilers/VisualBasic/Portable/VisualBasicCompilationOptions.vb @@ -351,6 +351,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return importNames.ToImmutableAndFree() End Function + Friend Overrides Function CreateDeterministicKeyBuilder() As DeterministicKeyBuilder + Return VisualBasicDeterministicKeyBuilder.Instance + End Function + ''' ''' Gets the global imports collection. ''' diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf index 629d5c1977535..74dbe4cd9e5b2 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf @@ -3992,7 +3992,7 @@ Expected closing ']]>' for XML CDATA section. - Očekávalo se ukončení oddílu CDATA kódu XML znaky ]]>. + Očekávalo se ukončení oddílu CDATA kódu XML znaky ']]>'. @@ -4007,7 +4007,7 @@ Expected beginning '<' for an XML tag. - Očekával se úvodní znak < značky XML. + Očekával se úvodní znak '<' značky XML. @@ -7395,7 +7395,7 @@ The literal string ']]>' is not allowed in element content. - V obsahu elementu není povolený řetězec literálu ]]>. + V obsahu elementu není povolený řetězec literálu ']]>'. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf index 6d7ee262248fe..aa9b5800ad529 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf @@ -3992,7 +3992,7 @@ Expected closing ']]>' for XML CDATA section. - ]]>' fermant attendu pour une section CDATA XML. + ']]>' fermant attendu pour une section CDATA XML. @@ -4007,7 +4007,7 @@ Expected beginning '<' for an XML tag. - <' ouvrant attendu pour une balise XML. + '<' ouvrant attendu pour une balise XML. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf index f566a2211eb7f..206d8737e4cb4 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf @@ -3992,7 +3992,7 @@ Expected closing ']]>' for XML CDATA section. - ]]>' de fechamento esperado para seção XML CDATA. + ']]>' de fechamento esperado para seção XML CDATA. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf index 5c401a33f945e..e6bbcbc2efa53 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf @@ -5119,7 +5119,7 @@ Operator declaration must be one of: +, -, *, \, /, ^, &, Like, Mod, And, Or, Xor, Not, <<, >>, =, <>, <, <=, >, >=, CType, IsTrue, IsFalse. - İşleç bildirimi şunlardan biri olmalıdır: +, -, *, \, /, ^, &, Like, Mod, And, Or, Xor, Not, <<, >>, =, <>, <, <=, >, >=, CType, IsTrue, IsFalse. + İşleç bildirimi şunlardan biri olmalıdır: +, -, *, \, /, ^, &, Like, Mod, And, Or, Xor, Not, <<,>>, =, <>, <, <=,>,>=, CType, IsTrue, IsFalse. @@ -5129,7 +5129,7 @@ Operator is not overloadable. Operator declaration must be one of: +, -, *, \, /, ^, &, Like, Mod, And, Or, Xor, Not, <<, >>, =, <>, <, <=, >, >=, CType, IsTrue, IsFalse. - İşleç aşırı yüklenebilir değil. İşleç bildirimi şunlardan biri olmalıdır: +, -, *, \, /, ^, &, Like, Mod, And, Or, Xor, Not, <<, >>, =, <>, <, <=, >, >=, CType, IsTrue, IsFalse. + İşleç aşırı yüklenebilir değil. İşleç bildirimi şunlardan biri olmalıdır: +, -, *, \, /, ^, &, Like, Mod, And, Or, Xor, Not, <<,>>, =, <>, <, <=,>,>=, CType, IsTrue, IsFalse. diff --git a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb index afe53e36bf789..a665e8204c9e6 100644 --- a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb +++ b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb @@ -337,6 +337,38 @@ End Module Assert.Equal("", output.ToString().Trim()) End Sub + + + Public Sub LogErrorsWithColumnNumbers() + ' Arguments with quoted rootnamespace and main type are unquoted when + ' the arguments are read in by the command line compiler. + Dim dir = Temp.CreateDirectory() + Dim file = dir.CreateDirectory("Test Path (123)").CreateFile("hellovb.vb").WriteAllText( +"Option Strict On +Module Module1 + + Property x As Integer = 3 + Sub Main() + x = 3.5 + asdf + End Sub +End Module +").Path + + Dim output As New StringWriter() + Dim compiler As New MockVisualBasicCompiler(Nothing, _baseDirectory, {"/nologo", "/target:exe", "/main:""Module1""", file}) + + Dim exitCode = compiler.Run(output, Nothing) + Assert.Equal(1, exitCode) + ' The errors and warnings generated by compiling this code are used in the test at + ' Microsoft.Build.Tasks.CodeAnalysis.UnitTests.CheckErrorAndWarningParsing() + Assert.Contains("\Test Path (123)\hellovb.vb(6) : warning BC40008: 'Public Property x As Integer' is obsolete.", output.ToString()) + Assert.Contains("\Test Path (123)\hellovb.vb(6) : error BC30512: Option Strict On disallows implicit conversions from 'Double' to 'Integer'.", output.ToString()) + Assert.Contains("\Test Path (123)\hellovb.vb(7) : error BC30451: 'asdf' is not declared. It may be inaccessible due to its protection level.", output.ToString()) + + CleanupAllGeneratedFiles(file) + End Sub + Public Sub CreateCompilationWithKeyFile() Dim source = " diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb index 5085180d99d03..77914f0881528 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb @@ -566,7 +566,7 @@ end class dependencies:={New ModuleData(en_usRef.Compilation.Assembly.Identity, OutputKind.DynamicallyLinkedLibrary, en_usRef.Compilation.EmitToArray(), - ImmutableArray(Of Byte).Empty, False)}). + ImmutableArray(Of Byte).Empty, False, False)}). VerifyDiagnostics() compilation = CreateCompilationWithMscorlib40AndReferences( @@ -599,11 +599,11 @@ end class dependencies:={New ModuleData(en_UKRef.Compilation.Assembly.Identity, OutputKind.DynamicallyLinkedLibrary, en_UKRef.Compilation.EmitToArray(), - ImmutableArray(Of Byte).Empty, False), + ImmutableArray(Of Byte).Empty, False, False), New ModuleData(neutralRef.Compilation.Assembly.Identity, OutputKind.DynamicallyLinkedLibrary, neutralRef.Compilation.EmitToArray(), - ImmutableArray(Of Byte).Empty, False)}, + ImmutableArray(Of Byte).Empty, False, False)}, sourceSymbolValidator:=Sub(m As ModuleSymbol) Assert.Equal(1, m.GetReferencedAssemblySymbols().Length) @@ -764,8 +764,10 @@ end class ]]> , options:=TestOptions.ReleaseDll, references:={hash_module}) + ' ILVerify: Assembly or module not found: hash_module CompileAndVerify(compilation, manifestResources:=hash_resources, + verify:=Verification.FailsILVerify, validator:=Sub(peAssembly) Dim reader = peAssembly.ManifestModule.GetMetadataReader() Dim assembly As AssemblyDefinition = reader.GetAssemblyDefinition() @@ -796,6 +798,7 @@ end class CompileAndVerify(compilation, manifestResources:=hash_resources, + verify:=Verification.FailsILVerify, validator:=Sub(peAssembly) Dim reader = peAssembly.ManifestModule.GetMetadataReader() Dim assembly As AssemblyDefinition = reader.GetAssemblyDefinition() @@ -826,6 +829,7 @@ end class CompileAndVerify(compilation, manifestResources:=hash_resources, + verify:=Verification.FailsILVerify, validator:=Sub(peAssembly) Dim reader = peAssembly.ManifestModule.GetMetadataReader() Dim assembly As AssemblyDefinition = reader.GetAssemblyDefinition() @@ -856,6 +860,7 @@ end class CompileAndVerify(compilation, manifestResources:=hash_resources, + verify:=Verification.FailsILVerify, validator:=Sub(peAssembly) Dim reader = peAssembly.ManifestModule.GetMetadataReader() Dim assembly As AssemblyDefinition = reader.GetAssemblyDefinition() @@ -994,6 +999,7 @@ end class , options:=TestOptions.ReleaseDll, references:={hash_module_Comp.EmitToImageReference()}) CompileAndVerify(compilation, + verify:=Verification.FailsILVerify, validator:=Sub(peAssembly) Dim metadataReader = peAssembly.ManifestModule.GetMetadataReader() Dim assembly As AssemblyDefinition = metadataReader.GetAssemblyDefinition() diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_StructLayout.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_StructLayout.vb index 959790bcc981e..01d8b03f30952 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_StructLayout.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_StructLayout.vb @@ -389,8 +389,8 @@ End Class End Sub CompileAndVerify(verifiable, validator:=validator) - CompileAndVerify(unverifiable, validator:=validator, verify:=Verification.Fails) - CompileAndVerify(unloadable, validator:=validator, verify:=Verification.Fails) + CompileAndVerify(unverifiable, validator:=validator, verify:=Verification.FailsPEVerify) + CompileAndVerify(unloadable, validator:=validator, verify:=Verification.FailsPEVerify) End Sub @@ -566,7 +566,7 @@ End Class ' type C can't be loaded - CompileAndVerify(source, verify:=Verification.Fails) + CompileAndVerify(source, verify:=Verification.FailsPEVerify) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb index 7cde3b5fc3519..86488cb5dacdb 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb @@ -6593,5 +6593,88 @@ second", Assert.Equal("transformNames", attribute.AttributeConstructor.Parameters.Single().Name) End Sub) End Sub + + + + Public Sub ErrorInPropertyValue_01() + Dim source = + + + public Function Count() as Integer + return 0 + end function +end class +]]> + + + + Dim compilation = CreateCompilation(source) + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]> + ) + End Sub + + + + Public Sub ErrorInPropertyValue_02() + Dim source = + + + public Function Count() as Integer + return 0 + end function +end class +]]> + + + + Dim compilation = CreateCompilation(source) + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +]]> + ) + End Sub + + + Public Sub ErrorInPropertyValue_03() + Dim source = + + +public structure S1 +end structure + + +public structure S2 +end structure +]]> + + + + Dim compilation = CreateCompilation(source) + compilation.AssertTheseDiagnostics( + + ~~~~~~~~~~~~ +BC30127: Attribute 'StructLayoutAttribute' is not valid: Incorrect argument value. + + ~~~~~~~~~~ +]]> + ) + End Sub End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenForeach.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenForeach.vb index 088a1e40c2787..b4eb840796ebd 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenForeach.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenForeach.vb @@ -2,6 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -2399,6 +2400,7 @@ End Class Public Sub NoObjectCopyForGetCurrent() + ' ILVerify: Unexpected type on the stack. { Offset = 25, Found = readonly address of '[...]C2+S1', Expected = address of '[...]C2+S1' } Dim TEMP = CompileAndVerify( @@ -2435,7 +2437,7 @@ End Class , expectedOutput:=).VerifyIL("C2.DoStuff", , verify:=Verification.FailsILVerify).VerifyIL("C2.DoStuff", ") Assert.Equal("System.Threading.Tasks.Task(Of Object)", methodData.Method.ReturnType.ToDisplayString()) methodData.VerifyIL( diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb index 350a25bdf25df..9aaee010a99c0 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb @@ -21,6 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Sub Bug776642a() + ' ILVerify: Unexpected type on the stack. { Offset = 16, Found = readonly address of '[...]OuterStruct', Expected = address of '[...]OuterStruct' } CompileAndVerify( @@ -51,7 +52,7 @@ Structure OuterStruct Public z As DoubleAndStruct End Structure -). +, verify:=Verification.FailsILVerify). VerifyIL("Program.M", Public Sub Bug776642a_ref() + ' ILVerify: Unexpected type on the stack. { Offset = 30, Found = readonly address of '[...]OuterStruct', Expected = address of '[...]OuterStruct' } CompileAndVerify( @@ -164,7 +166,7 @@ Structure OuterStruct Public z As DoubleAndStruct End Structure -). +, verify:=Verification.FailsILVerify). VerifyIL("Program.M", Public Sub TestGetObjectValueCalls() - + ' ILVerify null ref + ' Tracked by https//github.com/dotnet/roslyn/issues/58652 Dim verifier = CompileAndVerify( @@ -6286,7 +6289,7 @@ Module Program1 End Module -, references:={TestReferences.SymbolsTests.PropertiesWithByRef}) +, references:={TestReferences.SymbolsTests.PropertiesWithByRef}, verify:=Verification.FailsILVerify) verifier.VerifyIL("Module1.M", Public Sub GotoOutOfCatch() + ' ILVerify: Leave into try block. { Offset = 55 } CompileAndVerify( @@ -119,6 +121,7 @@ L2: End Module , +verify:=Verification.FailsILVerify, expectedOutput:="TryGoToCatchFinally"). VerifyIL("EmitTest.Main", -, references:={ValueTupleRef, SystemRuntimeFacadeRef, MscorlibRef_v46}, expectedOutput:=) +, references:={ValueTupleRef, SystemRuntimeFacadeRef, MscorlibRef_v46}, expectedOutput:=, verify:=Verification.FailsILVerify) verifier.VerifyDiagnostics() verifier.VerifyIL("C.VB$StateMachine_2_Test(Of SM$T).MoveNext()", -, references:={ValueTupleRef, SystemRuntimeFacadeRef, MscorlibRef_v46}, expectedOutput:=) +, references:={ValueTupleRef, SystemRuntimeFacadeRef, MscorlibRef_v46}, expectedOutput:=, verify:=Verification.FailsILVerify) verifier.VerifyDiagnostics() verifier.VerifyIL("C.VB$StateMachine_2_Test(Of SM$T).MoveNext()", Public Sub LongTupleWithSubstitution() - + ' ILVerify: + ' Failed to load type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' + ' Failed to load type 'System.Runtime.CompilerServices.YieldAwaitable' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' + ' Failed to load type 'System.Runtime.CompilerServices.IAsyncStateMachine' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' Dim verifier = CompileAndVerify( @@ -5296,7 +5299,7 @@ Class C End Function End Class -, references:={ValueTupleRef, SystemRuntimeFacadeRef, MscorlibRef_v46}, expectedOutput:=) +, references:={ValueTupleRef, SystemRuntimeFacadeRef, MscorlibRef_v46}, expectedOutput:=, verify:=Verification.FailsILVerify) verifier.VerifyDiagnostics() diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/WinRTCollectionTests.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/WinRTCollectionTests.vb index 0ad2dd394ef9d..b423ef412fa05 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/WinRTCollectionTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/WinRTCollectionTests.vb @@ -4207,9 +4207,12 @@ End Class + ' PEVerify: + ' [ : AllMembers::ValidateMethod][mdToken=0x6000003] [HRESULT 0x8000000F] - Typename or Namespace was not found in metadata file. + ' [ : AllMembers::TestExpressionTreeCompiler][mdToken=0x6000005][offset 0x00000007] Unable to resolve token. Dim verifier = CompileAndVerify(source, references:=LegacyRefs, - verify:=Verification.Fails) + verify:=Verification.FailsPEVerify) AssertNoErrorsOrWarnings(verifier) verifier.VerifyIL("AllMembers.TestExpressionTreeCompiler", Public Sub EmitMetadataOnly() - ' Check that Compilation.EmitMetadataOnly works. Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40( @@ -299,6 +298,295 @@ End Class End Using End Sub + + Public Sub EmitMetadataOnly_XmlDocs_NoDocMode_Success() + Dim compilation = CreateCompilationWithMscorlib40( + + +Imports System + +Namespace Goo.Bar + ''' <summary>This should be emitted</summary> + Public Class X + End Class +End Namespace + +, assemblyName:="test", parseOptions:=VisualBasicParseOptions.Default.WithDocumentationMode(DocumentationMode.None)) + + Dim emitResult As EmitResult + Dim mdOnlyImage As Byte() + Dim xmlDocBytes As Byte() + + Using output = New MemoryStream() + Using xmlStream = New MemoryStream() + emitResult = compilation.Emit(output, xmlDocumentationStream:=xmlStream, options:=New EmitOptions(metadataOnly:=True)) + mdOnlyImage = output.ToArray() + xmlDocBytes = xmlStream.ToArray() + End Using + End Using + + Assert.True(emitResult.Success) + emitResult.Diagnostics.Verify() + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted") + Assert.Equal( +" + + + +test + + + + + +", + Encoding.UTF8.GetString(xmlDocBytes)) + End Sub + + + Public Sub EmitMetadataOnly_XmlDocs_NoDocMode_SyntaxWarning() + Dim compilation = CreateCompilationWithMscorlib40( + + +Imports System + +Namespace Goo.Bar + ''' <summary>This should still emit + Public Class X + End Class +End Namespace + +, assemblyName:="test", parseOptions:=VisualBasicParseOptions.Default.WithDocumentationMode(DocumentationMode.None)) + + Dim emitResult As EmitResult + Dim mdOnlyImage As Byte() + Dim xmlDocBytes As Byte() + + Using output = New MemoryStream() + Using xmlStream = New MemoryStream() + emitResult = compilation.Emit(output, xmlDocumentationStream:=xmlStream, options:=New EmitOptions(metadataOnly:=True)) + mdOnlyImage = output.ToArray() + xmlDocBytes = xmlStream.ToArray() + End Using + End Using + + Assert.True(emitResult.Success) + emitResult.Diagnostics.Verify() + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted") + Assert.Equal( + " + + + +test + + + + + +", + Encoding.UTF8.GetString(xmlDocBytes)) + End Sub + + + Public Sub EmitMetadataOnly_XmlDocs_DiagnoseDocMode_SyntaxWarning() + Dim compilation = CreateCompilationWithMscorlib40( + + +Imports System + +Namespace Goo.Bar + ''' <summary>This should still emit + Public Class X + End Class +End Namespace + +, assemblyName:="test", parseOptions:=VisualBasicParseOptions.Default.WithDocumentationMode(DocumentationMode.Diagnose)) + + Dim emitResult As EmitResult + Dim mdOnlyImage As Byte() + Dim xmlDocBytes As Byte() + + Using output = New MemoryStream() + Using xmlStream = New MemoryStream() + emitResult = compilation.Emit(output, xmlDocumentationStream:=xmlStream, options:=New EmitOptions(metadataOnly:=True)) + mdOnlyImage = output.ToArray() + xmlDocBytes = xmlStream.ToArray() + End Using + End Using + + Assert.True(emitResult.Success) + emitResult.Diagnostics.Verify( + Diagnostic(ERRID.WRN_XMLDocParseError1, "").WithArguments("Element is missing an end tag.").WithLocation(4, 9), + Diagnostic(ERRID.WRN_XMLDocParseError1, "").WithArguments("Expected beginning '<' for an XML tag.").WithLocation(4, 40), + Diagnostic(ERRID.WRN_XMLDocParseError1, "").WithArguments("'>' expected.").WithLocation(4, 40)) + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted") + Assert.Equal( + " + + + +test + + + + + +", + Encoding.UTF8.GetString(xmlDocBytes)) + End Sub + + + Public Sub EmitMetadataOnly_XmlDocs_DiagnoseDocMode_SemanticWarning() + Dim compilation = CreateCompilationWithMscorlib40( + + +Imports System + +Namespace Goo.Bar + ''' <summary><see cref="T"/></summary> + Public Class X + End Class +End Namespace + +, assemblyName:="test", parseOptions:=VisualBasicParseOptions.Default.WithDocumentationMode(DocumentationMode.Diagnose)) + + Dim emitResult As EmitResult + Dim mdOnlyImage As Byte() + Dim xmlDocBytes As Byte() + + Using output = New MemoryStream() + Using xmlStream = New MemoryStream() + emitResult = compilation.Emit(output, xmlDocumentationStream:=xmlStream, options:=New EmitOptions(metadataOnly:=True)) + mdOnlyImage = output.ToArray() + xmlDocBytes = xmlStream.ToArray() + End Using + End Using + + Assert.True(emitResult.Success) + emitResult.Diagnostics.Verify( + Diagnostic(ERRID.WRN_XMLDocCrefAttributeNotFound1, "cref=""T""").WithArguments("T").WithLocation(4, 23)) + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted") + Assert.Equal( + " + + + +test + + + + + + + + +", + Encoding.UTF8.GetString(xmlDocBytes)) + End Sub + + + Public Sub EmitMetadataOnly_XmlDocs_DiagnoseDocMode_Success() + Dim compilation = CreateCompilationWithMscorlib40( + + +Imports System + +Namespace Goo.Bar + ''' <summary>This should emit</summary> + Public Class X + End Class +End Namespace + +, assemblyName:="test", parseOptions:=VisualBasicParseOptions.Default.WithDocumentationMode(DocumentationMode.Diagnose)) + + Dim emitResult As EmitResult + Dim mdOnlyImage As Byte() + Dim xmlDocBytes As Byte() + + Using output = New MemoryStream() + Using xmlStream = New MemoryStream() + emitResult = compilation.Emit(output, xmlDocumentationStream:=xmlStream, options:=New EmitOptions(metadataOnly:=True)) + mdOnlyImage = output.ToArray() + xmlDocBytes = xmlStream.ToArray() + End Using + End Using + + Assert.True(emitResult.Success) + emitResult.Diagnostics.Verify() + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted") + Assert.Equal( + " + + + +test + + + + + This should emit + + + +", + Encoding.UTF8.GetString(xmlDocBytes)) + End Sub + + + Public Sub EmitMetadataOnly_XmlDocs_ParseDocMode_Success() + Dim compilation = CreateCompilationWithMscorlib40( + + +Imports System + +Namespace Goo.Bar + ''' <summary>This should emit</summary> + Public Class X + End Class +End Namespace + +, assemblyName:="test", parseOptions:=VisualBasicParseOptions.Default.WithDocumentationMode(DocumentationMode.Parse)) + + Dim emitResult As EmitResult + Dim mdOnlyImage As Byte() + Dim xmlDocBytes As Byte() + + Using output = New MemoryStream() + Using xmlStream = New MemoryStream() + emitResult = compilation.Emit(output, xmlDocumentationStream:=xmlStream, options:=New EmitOptions(metadataOnly:=True)) + mdOnlyImage = output.ToArray() + xmlDocBytes = xmlStream.ToArray() + End Using + End Using + + Assert.True(emitResult.Success) + emitResult.Diagnostics.Verify() + + Assert.True(mdOnlyImage.Length > 0, "no metadata emitted") + Assert.Equal( + " + + + +test + + + + + This should emit + + + +", + Encoding.UTF8.GetString(xmlDocBytes)) + End Sub + Private Sub EmitRefAssembly_PrivatePropertyGetter() Dim source As String = " @@ -402,7 +690,8 @@ End Class" Dim comp = CreateEmptyCompilation({Parse("")}) comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_ReferenceAssemblyAttribute__ctor) - CompileAndVerify(comp, emitOptions:=emitRefAssembly, verify:=Verification.Passes, validator:=assemblyValidator) + ' ILVerify: Failed to load type 'System.String' from assembly ... + CompileAndVerify(comp, emitOptions:=emitRefAssembly, verify:=Verification.FailsILVerify, validator:=assemblyValidator) End Sub @@ -3560,7 +3849,7 @@ End Class Dim comp = CreateCompilationWithMscorlib40(source1, OutputKind.NetModule) Dim metadataRef = comp.EmitToImageReference() - CompileAndVerify(source2, references:={metadataRef}, options:=TestOptions.ReleaseModule, verify:=Verification.Fails) + CompileAndVerify(source2, references:={metadataRef}, options:=TestOptions.ReleaseModule, verify:=Verification.FailsPEVerify Or Verification.FailsILVerify) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.vb index f3be22ee50635..c0b6cca35d6b6 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/AssemblyReferencesTests.vb @@ -329,7 +329,8 @@ End Class Dim compilation0 = CreateCompilationWithMscorlib40({src0}, {ref01, ref11}, assemblyName:="C", options:=TestOptions.DebugDll) Dim compilation1 = compilation0.WithSource(src1).WithReferences({MscorlibRef, ref02, ref12}) - Dim v0 = CompileAndVerify(compilation0) + ' ILVerify: Failed to load type 'D1' from assembly 'Lib, Version=1.0.0.1, Culture=neutral, PublicKeyToken=ce65828c82a341f2' + Dim v0 = CompileAndVerify(compilation0, verify:=Verification.FailsILVerify) Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F") Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F") diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb index c2f752b822be3..775da1ebd068d 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb @@ -4679,7 +4679,7 @@ End Class Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)) - Dim v0 = CompileAndVerify(compilation0, verify:=Verification.Fails) + Dim v0 = CompileAndVerify(compilation0, verify:=Verification.FailsPEVerify) Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F") @@ -4756,7 +4756,7 @@ End Class Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)) - Dim v0 = CompileAndVerify(compilation0, verify:=Verification.Fails) + Dim v0 = CompileAndVerify(compilation0, verify:=Verification.FailsPEVerify) Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F") diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitMetadata.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitMetadata.vb index 7f88bb02b0849..9919b6883423f 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitMetadata.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitMetadata.vb @@ -269,7 +269,8 @@ End Class {mscorlibRef, multiModule}, TestOptions.ReleaseDll) - dllImage = CompileAndVerify(c2).EmittedAssemblyData + ' ILVerify: The method or operation is not implemented. + dllImage = CompileAndVerify(c2, verify:=Verification.FailsILVerify).EmittedAssemblyData Using metadata = AssemblyMetadata.CreateFromImage(dllImage) Dim emitAssemblyRefs2 As PEAssembly = metadata.GetAssembly @@ -307,7 +308,8 @@ End Class Dim class1 = c1.GlobalNamespace.GetMembers("Class1") Assert.Equal(1, class1.Count()) - Dim manifestModule = CompileAndVerify(c1).EmittedAssemblyData + ' ILVerify: Assembly or module not found: netModule1 + Dim manifestModule = CompileAndVerify(c1, verify:=Verification.FailsILVerify).EmittedAssemblyData Using metadata = AssemblyMetadata.Create(ModuleMetadata.CreateFromImage(manifestModule), netModule1, netModule2) Dim emitAddModule As PEAssembly = metadata.GetAssembly diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb index e6fe80e2af427..e921e126c1fa7 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb @@ -1533,7 +1533,8 @@ End Interface ]]> Dim compilation0 = CreateCompilationWithMscorlib40(sources0) - Dim verifier = CompileAndVerify(compilation0, verify:=Verification.Fails) + ' PEVerify: Error: Method cannot be both generic and defined on an imported type. + Dim verifier = CompileAndVerify(compilation0, verify:=Verification.FailsPEVerify) AssertTheseDiagnostics(verifier, ()) Dim validator As Action(Of ModuleSymbol) = Sub([module]) DirectCast([module], PEModuleSymbol).Module.PretendThereArentNoPiaLocalTypes() @@ -1603,13 +1604,13 @@ End Interface sources1, options:=TestOptions.DebugDll, references:={New VisualBasicCompilationReference(compilation0, embedInteropTypes:=True), SystemCoreRef}) - verifier = CompileAndVerify(compilation1, symbolValidator:=validator, verify:=Verification.Fails) + verifier = CompileAndVerify(compilation1, symbolValidator:=validator, verify:=Verification.FailsPEVerify) AssertTheseDiagnostics(verifier, ()) compilation1 = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences( sources1, options:=TestOptions.DebugDll, references:={compilation0.EmitToImageReference(embedInteropTypes:=True), SystemCoreRef}) - verifier = CompileAndVerify(compilation1, symbolValidator:=validator, verify:=Verification.Fails) + verifier = CompileAndVerify(compilation1, symbolValidator:=validator, verify:=Verification.FailsPEVerify) AssertTheseDiagnostics(verifier, ()) End Sub @@ -3711,12 +3712,12 @@ BC31539: Cannot find the interop type that matches the embedded type 'I1'. Are y Dim compilation3 = CreateCompilationWithMscorlib40AndReferences( consumer, references:={New VisualBasicCompilationReference(piaCompilation2)}) - CompileAndVerify(compilation3, verify:=Verification.Fails) + CompileAndVerify(compilation3, verify:=Verification.FailsPEVerify) Dim compilation4 = CreateCompilationWithMscorlib40AndReferences( consumer, references:={MetadataReference.CreateFromImage(piaCompilation2.EmitToArray())}) - CompileAndVerify(compilation4, verify:=Verification.Fails) + CompileAndVerify(compilation4, verify:=Verification.FailsPEVerify) End Sub @@ -4128,15 +4129,17 @@ BC36924: Type 'List(Of I1)' cannot be used across assembly boundaries because it VerifyEmitDiagnostics(compilation2, errors) VerifyEmitMetadataOnlyDiagnostics(compilation2) + ' PEVerify: [ : C::M][mdToken=0x6000002][offset 0x00000001] Unable to resolve token. Dim compilation3 = CreateCompilationWithMscorlib40AndReferences( consumer, references:={New VisualBasicCompilationReference(piaCompilation2)}) - CompileAndVerify(compilation3, verify:=Verification.Fails) + CompileAndVerify(compilation3, verify:=Verification.FailsPEVerify) + ' PEVerify: [ : C::M][mdToken=0x6000002][offset 0x00000001] Unable to resolve token. Dim compilation4 = CreateCompilationWithMscorlib40AndReferences( consumer, references:={MetadataReference.CreateFromImage(piaCompilation2.EmitToArray())}) - CompileAndVerify(compilation4, verify:=Verification.Fails) + CompileAndVerify(compilation4, verify:=Verification.FailsPEVerify) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/ExpressionTrees/CodeGenExprLambda.vb b/src/Compilers/VisualBasic/Test/Emit/ExpressionTrees/CodeGenExprLambda.vb index cd520e863fe3d..54e4c38a1c6e2 100644 --- a/src/Compilers/VisualBasic/Test/Emit/ExpressionTrees/CodeGenExprLambda.vb +++ b/src/Compilers/VisualBasic/Test/Emit/ExpressionTrees/CodeGenExprLambda.vb @@ -1820,7 +1820,8 @@ End Structure Optional checked As Boolean = True, Optional optimize As Boolean = True, Optional latestReferences As Boolean = False, - Optional addXmlReferences As Boolean = False) As CompilationVerifier + Optional addXmlReferences As Boolean = False, + Optional verify As Verification = Verification.Passes) As CompilationVerifier Debug.Assert(Not latestReferences OrElse Not addXmlReferences) ' NYI @@ -1833,7 +1834,8 @@ End Structure options:=If(optimize, TestOptions.ReleaseExe, TestOptions.DebugExe).WithOverflowChecks(checked), expectedOutput:=If(result IsNot Nothing, result.Trim, Nothing), references:=If(addXmlReferences, Net40XmlReferences, {}), - useLatestFramework:=latestReferences) + useLatestFramework:=latestReferences, + verify:=verify) End Function Private Sub TestExpressionTrees(sourceFile As XElement, result As String, @@ -1841,9 +1843,10 @@ End Structure Optional optimize As Boolean = True, Optional latestReferences As Boolean = False, Optional addXmlReferences As Boolean = False, - Optional diagnostics() As DiagnosticDescription = Nothing) + Optional diagnostics() As DiagnosticDescription = Nothing, + Optional verify As Verification = Verification.Passes) - TestExpressionTreesVerifier(sourceFile, result, checked, optimize, latestReferences, addXmlReferences).VerifyDiagnostics(If(diagnostics, {})) + TestExpressionTreesVerifier(sourceFile, result, checked, optimize, latestReferences, addXmlReferences, verify).VerifyDiagnostics(If(diagnostics, {})) End Sub Private Sub TestExpressionTrees(sourceFile As XElement, result As XCData, @@ -3667,6 +3670,7 @@ Lambda( Public Sub ExprTree_LegacyTests02_v40() + ' ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 1223 } Dim file = - TestExpressionTrees(file, ExpTreeTestResources.ExprTree_LegacyTests02_v40_Result) + TestExpressionTrees(file, ExpTreeTestResources.ExprTree_LegacyTests02_v40_Result, verify:=Verification.FailsILVerify) End Sub Public Sub ExprTree_LegacyTests02_v45() + ' ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 1167 } Dim file = - TestExpressionTrees(file, ExpTreeTestResources.ExprTree_LegacyTests02_v45_Result, latestReferences:=True) + TestExpressionTrees(file, ExpTreeTestResources.ExprTree_LegacyTests02_v45_Result, latestReferences:=True, verify:=Verification.FailsILVerify) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb index 032515496a3cf..8039de658d6eb 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb @@ -691,7 +691,8 @@ End Module - Dim v = CompileAndVerify(CreateCompilationWithMscorlib40AndVBRuntime(source, TestOptions.DebugExe)) + ' ILVerify: Leave into try block. { Offset = 75 } + Dim v = CompileAndVerify(CreateCompilationWithMscorlib40AndVBRuntime(source, TestOptions.DebugExe), verify:=Verification.FailsILVerify) v.VerifyIL("M1.Main", " { diff --git a/src/Compilers/VisualBasic/Test/Emit/XmlLiteralTests.vb b/src/Compilers/VisualBasic/Test/Emit/XmlLiteralTests.vb index f17c093a1af79..879062699732b 100644 --- a/src/Compilers/VisualBasic/Test/Emit/XmlLiteralTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/XmlLiteralTests.vb @@ -6,6 +6,7 @@ Imports System.IO Imports System.Text Imports Microsoft.Cci Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities @@ -2915,6 +2916,7 @@ End Module Public Sub ValueExtensionProperty() + ' ILVerify: Unexpected type on the stack. { Offset = 117, Found = ref '[mscorlib]System.Collections.Generic.IEnumerable`1', Expected = ref '[mscorlib]System.Collections.Generic.IEnumerable`1' } Dim compilation = CompileAndVerify( -, references:=Net40XmlReferences) +, references:=Net40XmlReferences, verify:=Verification.FailsILVerify) compilation.VerifyIL("M.M(Of T)", , references:={netModule1.EmitToImageReference(), netModule2.EmitToImageReference()}) assembly.VerifyDiagnostics() - CompileAndVerify(assembly) + ' ILVerify: Assembly or module not found: missing2 + CompileAndVerify(assembly, verify:=Verification.FailsILVerify) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/BinaryOperators.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/BinaryOperators.vb index 2e73394fdcc86..e71ee9ad697c2 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/BinaryOperators.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/BinaryOperators.vb @@ -1499,7 +1499,7 @@ End Module Private Sub EnumerateChildren(iop As IOperation, ByRef numChildren as Integer) numChildren += 1 Assert.NotNull(iop) - For Each child in iop.Children + For Each child In iop.ChildOperations EnumerateChildren(child, numChildren) Next End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb index 813cc68418b46..e7d1ea2c9a88b 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb @@ -1203,7 +1203,8 @@ End Class ' VB seems to allow methods that return TypedReference, likely for compat reasons ' that is technically not verifiable, but it is not relevant to this test - Dim verifier = CompileAndVerify(compilation, verify:=Verification.Fails, expectedOutput:= + ' PEVerify: [ : C1::F][mdToken=0x6000003][offset 0x00000013] Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. + Dim verifier = CompileAndVerify(compilation, verify:=Verification.FailsPEVerify, expectedOutput:= ) @@ -3998,6 +3999,7 @@ BC41999: Implicit conversion from 'I1' to 'C1' in copying the value of 'ByRef' p ~ ]]>) + ' ILVerify: Unexpected type on the stack. { Offset = 39, Found = readonly address of '[...]S1', Expected = address of '[...]S1' } Dim verifier = CompileAndVerify(compilation, expectedOutput:= ) +]]>, verify:=Verification.FailsILVerify) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/IReadOnlyListAndCollection.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/IReadOnlyListAndCollection.vb index 98d104745cea5..3ccdc37940797 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/IReadOnlyListAndCollection.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/IReadOnlyListAndCollection.vb @@ -2,6 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -115,6 +116,7 @@ End Module ) + ' ILVerify: Unexpected type on the stack. { Offset = 232, Found = ref 'int32[][]', Expected = ref '[mscorlib]System.Collections.Generic.IList`1>' } CompileAndVerify(compilation, ) +]]>, verify:=Verification.FailsILVerify) End Sub @@ -330,6 +332,7 @@ End Module ) + ' ILVerify: Unexpected type on the stack. { Offset = 232, Found = ref 'int32[][]', Expected = ref '[mscorlib]System.Collections.Generic.IList`1>' } CompileAndVerify(compilation, ) +]]>, verify:=Verification.FailsILVerify) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/UseSiteErrorTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/UseSiteErrorTests.vb index fd4065bf7f78e..0ba35cee30ca1 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/UseSiteErrorTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/UseSiteErrorTests.vb @@ -665,7 +665,8 @@ BC30652: Reference required to assembly 'mincorlib, Version=0.0.0.0, Culture=neu Dim compilation5 = CreateEmptyCompilationWithReferences(source2, options:=TestOptions.ReleaseDll, references:={compilation1.ToMetadataReference()}) compilation5.VerifyEmitDiagnostics() - CompileAndVerify(compilation5) + ' ILVerify: no corlib + CompileAndVerify(compilation5, verify:=Verification.FailsILVerify) Assert.Equal(TypeKind.Struct, compilation5.GetTypeByMetadataName("A").TypeKind) Assert.Equal(TypeKind.Enum, compilation5.GetTypeByMetadataName("B").TypeKind) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/DefaultInterfaceImplementationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/DefaultInterfaceImplementationTests.vb index 9bda13dc25580..e98e65e6d84cf 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/DefaultInterfaceImplementationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/DefaultInterfaceImplementationTests.vb @@ -30,7 +30,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests compilationOptions:=compilationOptions) End Function - Private Shared ReadOnly Property VerifyOnMonoOrCoreClr As Verification + Private Shared ReadOnly Property VerifyFailsOnMonoOrCoreClr As Verification + Get + Return If(ExecutionConditionUtil.IsMonoOrCoreClr, Verification.Fails, Verification.Skipped) + End Get + End Property + + Private Shared ReadOnly Property VerifyPassesOnMonoOrCoreClr As Verification Get Return If(ExecutionConditionUtil.IsMonoOrCoreClr, Verification.Passes, Verification.Skipped) End Get @@ -108,7 +114,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -191,7 +197,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -268,7 +274,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -345,7 +351,8 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + ' ILVerify: Method is not visible. { Offset = 8 } + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -387,7 +394,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -527,7 +534,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -559,7 +566,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -745,7 +752,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -831,7 +838,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -870,7 +877,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -1380,7 +1387,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -1449,7 +1456,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -1478,7 +1485,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.M1", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -1777,7 +1784,7 @@ End Class Dim comp1 = CreateCompilation(source1, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, verify:=VerifyOnMonoOrCoreClr).VerifyDiagnostics() + CompileAndVerify(comp1, verify:=VerifyPassesOnMonoOrCoreClr).VerifyDiagnostics() End Sub @@ -1867,7 +1874,7 @@ End Class Dim comp1 = CreateCompilation(source1, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, verify:=VerifyOnMonoOrCoreClr).VerifyDiagnostics() + CompileAndVerify(comp1, verify:=VerifyPassesOnMonoOrCoreClr).VerifyDiagnostics() End Sub Private Const NoPiaAttributes As String = " @@ -2404,7 +2411,7 @@ public interface ITest33 For Each reference2 In {compilation1.ToMetadataReference(), compilation1.EmitToImageReference()} Dim compilation2 = CreateCompilation(consumer2, options:=TestOptions.ReleaseExe, references:={reference2, pia2Reference}) - CompileAndVerify(compilation2, expectedOutput:="Test.M1") + CompileAndVerify(compilation2, expectedOutput:="Test.M1", verify:=Verification.FailsILVerify) Next End Sub @@ -2529,7 +2536,7 @@ End Class I1+T2 I1+T3 B -I1+T5", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1+T5", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -2753,7 +2760,7 @@ End Class I1+T2 I1+T3 B -I1+T5", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1+T5", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -3223,7 +3230,7 @@ End Interface I1+T2 I1+T3 B -I1+T5", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1+T5", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -3292,7 +3299,7 @@ End Interface I1+T2 I1+T3 B -I1+T5", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1+T5", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -3512,7 +3519,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugDll, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, verify:=VerifyOnMonoOrCoreClr).VerifyDiagnostics() + CompileAndVerify(comp1, verify:=VerifyPassesOnMonoOrCoreClr).VerifyDiagnostics() End Sub @@ -3666,7 +3673,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugDll, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, verify:=VerifyOnMonoOrCoreClr).VerifyDiagnostics() + CompileAndVerify(comp1, verify:=VerifyPassesOnMonoOrCoreClr).VerifyDiagnostics() End Sub @@ -3811,7 +3818,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get -C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -3894,7 +3901,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get -C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -3979,7 +3986,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get -C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -4172,7 +4179,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get -C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -4221,7 +4228,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get -C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -4270,7 +4277,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get -C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -4319,7 +4326,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get -C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -4368,7 +4375,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get -C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -4417,7 +4424,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get -C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -4625,10 +4632,10 @@ End Class Assert.Empty(p1Get.ExplicitInterfaceImplementations) End Sub - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) End Sub @@ -4686,10 +4693,10 @@ End Class Assert.Empty(p1Get.ExplicitInterfaceImplementations) End Sub - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) End Sub @@ -4753,10 +4760,10 @@ End Class Assert.Empty(p1Set.ExplicitInterfaceImplementations) End Sub - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) End Sub @@ -4816,10 +4823,10 @@ End Class Assert.Empty(p1Set.ExplicitInterfaceImplementations) End Sub - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) End Sub @@ -4856,10 +4863,10 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -4897,10 +4904,10 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -4937,10 +4944,10 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -5127,7 +5134,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -5157,7 +5164,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -5187,7 +5194,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -5217,7 +5224,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -5247,7 +5254,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -5277,7 +5284,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -5780,7 +5787,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get -I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -5957,7 +5964,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get -I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -5999,7 +6006,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get -I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -6041,7 +6048,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get -I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -6083,7 +6090,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get -I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -6125,7 +6132,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get -I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -6167,7 +6174,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get -I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -7460,7 +7467,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -7538,7 +7545,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -7618,7 +7625,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -7708,7 +7715,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -7752,7 +7759,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Get", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -7894,7 +7901,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -7923,7 +7930,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -8103,7 +8110,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -8187,7 +8194,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -8226,7 +8233,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Get", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -8721,7 +8728,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -8798,7 +8805,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -8877,7 +8884,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -8966,7 +8973,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -9009,7 +9016,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -9156,7 +9163,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -9188,7 +9195,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "100", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -9368,7 +9375,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Set", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -9452,7 +9459,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -9491,7 +9498,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Set", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Set", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -9994,7 +10001,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Add -C.P1.Remove", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Remove", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -10079,7 +10086,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Add -C.P1.Remove", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Remove", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -10166,7 +10173,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Add -C.P1.Remove", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Remove", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -10266,7 +10273,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Add -C.P1.Remove", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Remove", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -10317,7 +10324,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.P1.Add -C.P1.Remove", Nothing), verify:=VerifyOnMonoOrCoreClr) +C.P1.Remove", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -10408,7 +10415,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "M1 -M2", Nothing), verify:=VerifyOnMonoOrCoreClr) +M2", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -10499,7 +10506,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "M1 -M2", Nothing), verify:=VerifyOnMonoOrCoreClr) +M2", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -10542,7 +10549,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "M1 -M2", Nothing), verify:=VerifyOnMonoOrCoreClr) +M2", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -10749,7 +10756,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Add -I1.P1.Remove", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Remove", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -10844,7 +10851,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Add -I1.P1.Remove", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Remove", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -10887,7 +10894,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "I1.P1.Add -I1.P1.Remove", Nothing), verify:=VerifyOnMonoOrCoreClr) +I1.P1.Remove", Nothing), verify:=VerifyFailsOnMonoOrCoreClr) End Sub @@ -11407,7 +11414,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -11489,7 +11496,7 @@ End Class Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.NetCoreApp, references:={csCompilation}) - CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyOnMonoOrCoreClr) + CompileAndVerify(comp1, expectedOutput:=If(ExecutionConditionUtil.IsMonoOrCoreClr, "C.M1", Nothing), verify:=VerifyPassesOnMonoOrCoreClr) End Sub @@ -11878,7 +11885,7 @@ End Class Assert.Same(i1WinRT.RemoveMethod, i2WinRT.RemoveMethod.ExplicitInterfaceImplementations.Single()) End Sub - CompileAndVerify(comp1, verify:=VerifyOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) + CompileAndVerify(comp1, verify:=VerifyPassesOnMonoOrCoreClr, sourceSymbolValidator:=validator, symbolValidator:=validator) End Sub End Class diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/ExtensionMethods/AddressOf.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/ExtensionMethods/AddressOf.vb index ac7b6137f72f3..d5d6701c9c453 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/ExtensionMethods/AddressOf.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/ExtensionMethods/AddressOf.vb @@ -202,6 +202,7 @@ End Namespace CompileAndVerify(compilationDef, + verify:=Verification.FailsILVerify, expectedOutput:= CompileAndVerify(compilationDef, + verify:=Verification.FailsILVerify, expectedOutput:= - + ' ILVerify: Unrecognized arguments for delegate .ctor. { Offset = 8 } CompileAndVerify(compilationDef, + verify:=Verification.FailsILVerify, expectedOutput:= - CompileAndVerify(compilation).VerifyIL("abcdef.goo", expectedIL.Value()) + ' ILVerify: Missing method 'System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken Windows.UI.Xaml.Application.add_Suspending(Windows.UI.Xaml.SuspendingEventHandler)' + CompileAndVerify(compilation, verify:=Verification.FailsILVerify).VerifyIL("abcdef.goo", expectedIL.Value()) End Sub diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/NoPia.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/NoPia.vb index 9d416fc9e17f5..d5a5efb4d870d 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/NoPia.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/NoPia.vb @@ -1633,7 +1633,8 @@ End Class references:={New VisualBasicCompilationReference(multiModule), New VisualBasicCompilationReference(pia1)}) - CompileAndVerify(consumer) + ' ILVerify: The method or operation is not implemented. + CompileAndVerify(consumer, verify:=Verification.FailsILVerify) End Sub diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb index b61ce12c60488..2130889a6d0a2 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb @@ -943,7 +943,8 @@ End Namespace 'Retargetted - should result in No additional Errors also and same runtime behavior Dim RetargetReference = RetargetCompilationToV2MsCorlib(referenceLibrary_Compilation) - Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, + ' ILVerify: Multiple modules named 'mscorlib' were found + Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, verify:=Verification.FailsILVerify, expectedOutput:=) Main_Retarget.VerifyDiagnostics() @@ -1307,7 +1308,8 @@ End Namespace '//Retargetted - should result in No Errors also and same runtime behavior Dim RetargetReference = RetargetCompilationToV2MsCorlib(referenceLibrary_Compilation) - Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, + ' ILVerify: Multiple modules named 'mscorlib' were found + Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, verify:=Verification.FailsILVerify, expectedOutput:=) Main_Retarget.VerifyDiagnostics() @@ -1693,7 +1695,8 @@ Imports System '//Retargetted - should result in No Errors also and same runtime behavior Dim RetargetReference = RetargetCompilationToV2MsCorlib(referenceLibrary_Compilation) - Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, + ' ILVerify: Multiple modules named 'mscorlib' were found + Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, verify:=Verification.FailsILVerify, expectedOutput:=) '//Retargetted - should result in No Errors also and same runtime behavior Dim RetargetReference = RetargetCompilationToV2MsCorlib(referenceLibrary_Compilation) - Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, + ' ILVerify: Multiple modules named 'mscorlib' were found + Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, verify:=Verification.FailsILVerify, expectedOutput:=) @@ -2686,7 +2692,8 @@ End Class ''//Retargetted - should result in No Errors also Dim RetargetReference = RetargetCompilationToV2MsCorlib(referenceLibrary_Compilation) - Dim Main_Retarget = CompileAndVerify(sourceMain, references:={RetargetReference}, options:=TestOptions.ReleaseExe) + ' ILVerify: Multiple modules named 'mscorlib' were found + Dim Main_Retarget = CompileAndVerify(sourceMain, references:={RetargetReference}, options:=TestOptions.ReleaseExe, verify:=Verification.FailsILVerify) main_NoRetarget.VerifyDiagnostics() End Sub @@ -3081,7 +3088,8 @@ End Namespace '//Retargetted - should result in No Errors also and same runtime behavior Dim RetargetReference = RetargetCompilationToV2MsCorlib(referenceLibrary_Compilation) - Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, + ' ILVerify: Multiple modules named 'mscorlib' were found + Dim Main_Retarget = CompileAndVerify(source, references:={RetargetReference}, options:=TestOptions.ReleaseExe, verify:=Verification.FailsILVerify, expectedOutput:=) Main_Retarget.VerifyDiagnostics() diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/TypeTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/TypeTests.vb index 7545421a135de..2592d264fd2c3 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/TypeTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/TypeTests.vb @@ -3199,7 +3199,7 @@ BC37218: Type 'ns.CF2' forwarded to assembly 'ForwardedTypes1, Version=0.0.0.0, }, TestOptions.ReleaseDll) ' Exported types in .NET modules cause PEVerify to fail. - CompileAndVerify(compilation, verify:=Verification.Fails).VerifyDiagnostics() + CompileAndVerify(compilation, verify:=Verification.FailsPEVerify).VerifyDiagnostics() compilation = CreateCompilationWithMscorlib40AndReferences(emptySource, { diff --git a/src/Compilers/VisualBasic/Test/Symbol/UsedAssembliesTests.vb b/src/Compilers/VisualBasic/Test/Symbol/UsedAssembliesTests.vb index 91f9706dc4e0b..55172dbecf44f 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/UsedAssembliesTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/UsedAssembliesTests.vb @@ -26,7 +26,8 @@ End Interface Dim comp1 = CreateEmptyCompilation(source) - CompileAndVerify(comp1) + ' ILVerify: Failed to load type 'System.String' from assembly ... + CompileAndVerify(comp1, verify:=Verification.FailsILVerify) Assert.Empty(comp1.GetUsedAssemblyReferences()) @@ -48,7 +49,7 @@ End Interface Dim comp1 = CreateEmptyCompilation(source) - CompileAndVerify(comp1) + CompileAndVerify(comp1, verify:=Verification.FailsILVerify) Dim source2 = @@ -235,7 +236,7 @@ End Interface Dim comp1 = CreateEmptyCompilation(source) - CompileAndVerify(comp1) + CompileAndVerify(comp1, verify:=Verification.FailsILVerify) Dim source2 = diff --git a/src/Dependencies/Collections/Internal/ArraySortHelper.cs b/src/Dependencies/Collections/Internal/ArraySortHelper.cs index 483eb46b5171d..6387b11161978 100644 --- a/src/Dependencies/Collections/Internal/ArraySortHelper.cs +++ b/src/Dependencies/Collections/Internal/ArraySortHelper.cs @@ -19,10 +19,6 @@ using System.Runtime.InteropServices; #endif -#if !NET5_0_OR_GREATER -using Half = System.Single; -#endif - namespace Microsoft.CodeAnalysis.Collections.Internal { #region ArraySortHelper for single arrays @@ -304,9 +300,12 @@ public static void Sort(SegmentedArraySegment keys, IComparer? comparer) // For floating-point, do a pre-pass to move all NaNs to the beginning // so that we can do an optimized comparison as part of the actual sort // on the remainder of the values. - if (typeof(T) == typeof(double) || - typeof(T) == typeof(float) || - typeof(T) == typeof(Half)) + if (typeof(T) == typeof(double) + || typeof(T) == typeof(float) +#if NET + || typeof(T) == typeof(Half) +#endif + ) { int nanLeft = SegmentedArraySortUtils.MoveNansToFront(keys, default(Span)); if (nanLeft == keys.Length) @@ -619,8 +618,10 @@ private static bool LessThan(ref T left, ref T right) return (float)(object)left < (float)(object)right ? true : false; if (typeof(T) == typeof(double)) return (double)(object)left < (double)(object)right ? true : false; +#if NET if (typeof(T) == typeof(Half)) return (Half)(object)left < (Half)(object)right ? true : false; +#endif return left.CompareTo(right) < 0 ? true : false; } @@ -651,8 +652,10 @@ private static bool GreaterThan(ref T left, ref T right) return (float)(object)left > (float)(object)right ? true : false; if (typeof(T) == typeof(double)) return (double)(object)left > (double)(object)right ? true : false; +#if NET if (typeof(T) == typeof(Half)) return (Half)(object)left > (Half)(object)right ? true : false; +#endif return left.CompareTo(right) > 0 ? true : false; } } @@ -902,9 +905,12 @@ public static void Sort(SegmentedArraySegment keys, Span values, I // For floating-point, do a pre-pass to move all NaNs to the beginning // so that we can do an optimized comparison as part of the actual sort // on the remainder of the values. - if (typeof(TKey) == typeof(double) || - typeof(TKey) == typeof(float) || - typeof(TKey) == typeof(Half)) + if (typeof(TKey) == typeof(double) + || typeof(TKey) == typeof(float) +#if NET + || typeof(TKey) == typeof(Half) +#endif + ) { int nanLeft = SegmentedArraySortUtils.MoveNansToFront(keys, values); if (nanLeft == keys.Length) @@ -1169,8 +1175,10 @@ private static bool LessThan(ref TKey left, ref TKey right) return (float)(object)left < (float)(object)right ? true : false; if (typeof(TKey) == typeof(double)) return (double)(object)left < (double)(object)right ? true : false; +#if NET if (typeof(TKey) == typeof(Half)) return (Half)(object)left < (Half)(object)right ? true : false; +#endif return left.CompareTo(right) < 0 ? true : false; } @@ -1201,8 +1209,10 @@ private static bool GreaterThan(ref TKey left, ref TKey right) return (float)(object)left > (float)(object)right ? true : false; if (typeof(TKey) == typeof(double)) return (double)(object)left > (double)(object)right ? true : false; +#if NET if (typeof(TKey) == typeof(Half)) return (Half)(object)left > (Half)(object)right ? true : false; +#endif return left.CompareTo(right) > 0 ? true : false; } } @@ -1230,9 +1240,12 @@ public static int MoveNansToFront(SegmentedArraySegment keys for (int i = 0; i < keys.Length; i++) { - if ((typeof(TKey) == typeof(double) && double.IsNaN((double)(object)keys[i])) || - (typeof(TKey) == typeof(float) && float.IsNaN((float)(object)keys[i])) || - (typeof(TKey) == typeof(Half) && Half.IsNaN((Half)(object)keys[i]))) + if ((typeof(TKey) == typeof(double) && double.IsNaN((double)(object)keys[i])) + || (typeof(TKey) == typeof(float) && float.IsNaN((float)(object)keys[i])) +#if NET + || (typeof(TKey) == typeof(Half) && Half.IsNaN((Half)(object)keys[i])) +#endif + ) { TKey temp = keys[left]; keys[left] = keys[i]; diff --git a/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.Package.csproj b/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.Package.csproj index 22cab2f5f0367..d183bbae6a578 100644 --- a/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.Package.csproj +++ b/src/Dependencies/Collections/Microsoft.CodeAnalysis.Collections.Package.csproj @@ -2,7 +2,7 @@ - netcoreapp3.1;netstandard2.0 + net6.0;netcoreapp3.1;netstandard2.0 false none false diff --git a/src/Dependencies/Collections/SegmentedList`1.cs b/src/Dependencies/Collections/SegmentedList`1.cs index 29124a87b9a8c..24bba65688740 100644 --- a/src/Dependencies/Collections/SegmentedList`1.cs +++ b/src/Dependencies/Collections/SegmentedList`1.cs @@ -1107,11 +1107,7 @@ public void Sort(Comparison comparison) if (_size > 1) { -#if NET - _items.AsSpan(0, _size).Sort(comparison); -#else SegmentedArray.Sort(_items, 0, _size, Comparer.Create(comparison)); -#endif } _version++; } diff --git a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler.cs b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler.cs index 3462f253cac28..0962222aa5239 100644 --- a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler.cs +++ b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler.cs @@ -108,14 +108,14 @@ protected override Document FormatAndApplyBasedOnEndToken(Document document, int return document; } - var options = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken); - - var changes = Formatter.GetFormattedTextChanges( + var options = SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); + var formatter = document.GetRequiredLanguageService(); + var changes = formatter.GetFormattingResult( root, SpecializedCollections.SingletonCollection(CommonFormattingHelpers.GetFormattingSpan(root, span.Value)), - document.Project.Solution.Workspace, options, - cancellationToken: cancellationToken); + rules: null, + cancellationToken).GetTextChanges(cancellationToken); return document.ApplyTextChanges(changes, cancellationToken); } diff --git a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs index 3e1503a8cba27..282c438001c49 100644 --- a/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs +++ b/src/EditorFeatures/CSharp/AutomaticCompletion/AutomaticLineEnderCommandHandler_Helpers.cs @@ -27,9 +27,11 @@ private static (SyntaxNode newRoot, int nextCaretPosition) ReplaceStatementOwner SyntaxNode newNode, SyntaxNode anchorNode, ImmutableArray nodesToInsert, + DocumentOptionSet documentOptions, CancellationToken cancellationToken) { - var rootEditor = new SyntaxEditor(root, document.Project.Solution.Workspace); + var services = document.Project.Solution.Workspace.Services; + var rootEditor = new SyntaxEditor(root, services); // 1. Insert the node before anchor node rootEditor.InsertAfter(anchorNode, nodesToInsert); @@ -40,11 +42,15 @@ private static (SyntaxNode newRoot, int nextCaretPosition) ReplaceStatementOwner // 4. Format the new node so that the inserted braces/blocks would have correct indentation and formatting. var newNodeAfterInsertion = newRoot.GetAnnotatedNodes(s_replacementNodeAnnotation).Single(); + + var options = SyntaxFormattingOptions.Create(documentOptions, services, root.Language); + var formattedNewRoot = Formatter.Format( newRoot, newNodeAfterInsertion.Span, - document.Project.Solution.Workspace, - cancellationToken: cancellationToken); + services, + options, + cancellationToken); // 4. Use the annotation to find the end of the open brace, it would be the new caret position var nextCaretPosition = formattedNewRoot.GetAnnotatedTokens(s_openBracePositionAnnotation).Single().Span.End; @@ -70,11 +76,11 @@ private static SyntaxNode ReplaceNodeAndFormat( var newNodeAfterInsertion = newRoot.GetAnnotatedNodes(s_replacementNodeAnnotation).Single(); // 4. Format the new node so that the inserted braces/blocks would have correct indentation and formatting. - var options = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken); + var options = SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); var formattedNewRoot = Formatter.Format( newRoot, newNodeAfterInsertion.Span, - document.Project.Solution.Workspace, + document.Project.Solution.Workspace.Services, options, cancellationToken: cancellationToken); return formattedNewRoot; @@ -145,6 +151,7 @@ WhileStatementSyntax or ForEachStatementSyntax or ForStatementSyntax or LockStat newNode: AddBlockToEmbeddedStatementOwner(embeddedStatementOwner, documentOptions), anchorNode: embeddedStatementOwner, nodesToInsert: ImmutableArray.Empty.Add(statement), + documentOptions, cancellationToken), DoStatementSyntax doStatementNode => AddBraceToDoStatement(document, root, doStatementNode, documentOptions, statement, cancellationToken), IfStatementSyntax ifStatementNode => AddBraceToIfStatement(document, root, ifStatementNode, documentOptions, statement, cancellationToken), @@ -184,6 +191,7 @@ private static (SyntaxNode newRoot, int nextCaretPosition) AddBraceToDoStatement newNode: AddBlockToEmbeddedStatementOwner(doStatementNode, documentOptions), anchorNode: doStatementNode, nodesToInsert: ImmutableArray.Empty.Add(innerStatement), + documentOptions, cancellationToken); } @@ -236,6 +244,7 @@ private static (SyntaxNode newRoot, int nextCaretPosition) AddBraceToIfStatement AddBlockToEmbeddedStatementOwner(ifStatementNode, documentOptions), ifStatementNode, ImmutableArray.Empty.Add(innerStatement), + documentOptions, cancellationToken); } @@ -300,6 +309,7 @@ private static (SyntaxNode newRoot, int nextCaretPosition) AddBraceToElseClause( WithBraces(elseClauseNode, documentOptions), elseClauseNode.Parent!, ImmutableArray.Empty.Add(innerStatement), + documentOptions, cancellationToken); } diff --git a/src/EditorFeatures/CSharp/CSharpEditorResources.resx b/src/EditorFeatures/CSharp/CSharpEditorResources.resx index b08d5121aba06..2e8072dc4f4d2 100644 --- a/src/EditorFeatures/CSharp/CSharpEditorResources.resx +++ b/src/EditorFeatures/CSharp/CSharpEditorResources.resx @@ -185,4 +185,10 @@ Outside namespace + + Split raw string + + + Grow raw string + \ No newline at end of file diff --git a/src/EditorFeatures/CSharp/DecompiledSource/AssemblyResolver.cs b/src/EditorFeatures/CSharp/DecompiledSource/AssemblyResolver.cs index 1867e385d3099..df3bbba9b5e4a 100644 --- a/src/EditorFeatures/CSharp/DecompiledSource/AssemblyResolver.cs +++ b/src/EditorFeatures/CSharp/DecompiledSource/AssemblyResolver.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Reflection.PortableExecutable; using System.Text; +using System.Threading.Tasks; using ICSharpCode.Decompiler.Metadata; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -48,10 +49,14 @@ void BuildReferenceCache() } } - bool IAssemblyResolver.IsGacAssembly(IAssemblyReference reference) + public Task ResolveAsync(IAssemblyReference name) { - // This method is not called by the decompiler - throw new NotSupportedException(); + return Task.FromResult(Resolve(name)); + } + + public Task ResolveModuleAsync(PEFile mainModule, string moduleName) + { + return Task.FromResult(ResolveModule(mainModule, moduleName)); } [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Could be non-static if instance data is accessed")] diff --git a/src/EditorFeatures/CSharp/DecompiledSource/CSharpDecompiledSourceService.cs b/src/EditorFeatures/CSharp/DecompiledSource/CSharpDecompiledSourceService.cs index 965cd834f56e8..7aaa67d7c011f 100644 --- a/src/EditorFeatures/CSharp/DecompiledSource/CSharpDecompiledSourceService.cs +++ b/src/EditorFeatures/CSharp/DecompiledSource/CSharpDecompiledSourceService.cs @@ -85,11 +85,13 @@ public async Task AddSourceToAsync(Document document, Compilation symb public static async Task FormatDocumentAsync(Document document, CancellationToken cancellationToken) { var node = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var options = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); // Apply formatting rules var formattedDoc = await Formatter.FormatAsync( - document, SpecializedCollections.SingletonEnumerable(node.FullSpan), - options: null, + document, + SpecializedCollections.SingletonEnumerable(node.FullSpan), + options, CSharpDecompiledSourceFormattingRule.Instance.Concat(Formatter.GetDefaultFormattingRules(document)), cancellationToken).ConfigureAwait(false); @@ -108,7 +110,7 @@ private static Document PerformDecompilation(Document document, string fullName, if (file is null && assemblyLocation is null) { - throw new NotSupportedException(EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret); + throw new NotSupportedException(FeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret); } file ??= new PEFile(assemblyLocation, PEStreamOptions.PrefetchEntireImage); diff --git a/src/EditorFeatures/CSharp/EmbeddedLanguages/CSharpEmbeddedLanguageEditorFeaturesProvider.cs b/src/EditorFeatures/CSharp/EmbeddedLanguages/CSharpEmbeddedLanguageEditorFeaturesProvider.cs index 8b667f4626ba2..0c5f1bce25d90 100644 --- a/src/EditorFeatures/CSharp/EmbeddedLanguages/CSharpEmbeddedLanguageEditorFeaturesProvider.cs +++ b/src/EditorFeatures/CSharp/EmbeddedLanguages/CSharpEmbeddedLanguageEditorFeaturesProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.LanguageServices; @@ -24,7 +22,7 @@ public CSharpEmbeddedLanguageEditorFeaturesProvider() { } - internal override string EscapeText(string text, SyntaxToken token) + public override string EscapeText(string text, SyntaxToken token) => EmbeddedLanguageUtilities.EscapeText(text, token); } } diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index a66120dc6f69e..2917e781f5ed1 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; @@ -18,6 +19,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; @@ -156,7 +158,8 @@ private Solution CreateSolutionWithEventHandler( var documentWithNameAndAnnotationsAdded = AddMethodNameAndAnnotationsToSolution(document, eventHandlerMethodName, position, plusEqualsTokenAnnotation, cancellationToken); var semanticDocument = SemanticDocument.CreateAsync(documentWithNameAndAnnotationsAdded, cancellationToken).WaitAndGetResult(cancellationToken); - var updatedRoot = AddGeneratedHandlerMethodToSolution(semanticDocument, eventHandlerMethodName, plusEqualsTokenAnnotation, cancellationToken); + var preferences = CSharpCodeGenerationPreferences.FromDocumentAsync(semanticDocument.Document, cancellationToken).WaitAndGetResult(cancellationToken); + var updatedRoot = AddGeneratedHandlerMethodToSolution(semanticDocument, preferences, eventHandlerMethodName, plusEqualsTokenAnnotation, cancellationToken); if (updatedRoot == null) { @@ -216,6 +219,7 @@ private static Document AddMethodNameAndAnnotationsToSolution( private static SyntaxNode AddGeneratedHandlerMethodToSolution( SemanticDocument document, + CSharpCodeGenerationPreferences preferences, string eventHandlerMethodName, SyntaxAnnotation plusEqualsTokenAnnotation, CancellationToken cancellationToken) @@ -234,7 +238,12 @@ private static SyntaxNode AddGeneratedHandlerMethodToSolution( var container = (SyntaxNode)typeDecl ?? eventHookupExpression.GetAncestor(); - var newContainer = CodeGenerator.AddMethodDeclaration(container, generatedMethodSymbol, document.Project.Solution.Workspace, new CodeGenerationOptions(afterThisLocation: eventHookupExpression.GetLocation())); + var codeGenerator = document.Document.GetRequiredLanguageService(); + + var codeGenOptions = preferences.GetOptions( + new CodeGenerationContext(afterThisLocation: eventHookupExpression.GetLocation())); + + var newContainer = codeGenerator.AddMethod(container, generatedMethodSymbol, codeGenOptions, cancellationToken); return root.ReplaceNode(container, newContainer); } diff --git a/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesLSPService.cs b/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesLSPService.cs index 65c94d977d0fa..4d0e18b085f6a 100644 --- a/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesLSPService.cs +++ b/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesLSPService.cs @@ -2,12 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; -using Microsoft.CodeAnalysis.Editor.FindUsages; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.Editor.CSharp.FindUsages diff --git a/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesService.cs b/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesService.cs index 1fedd08ae3d7c..b4b4a85aa40a9 100644 --- a/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesService.cs +++ b/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesService.cs @@ -4,7 +4,7 @@ using System; using System.Composition; -using Microsoft.CodeAnalysis.Editor.FindUsages; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.Editor.CSharp.FindUsages diff --git a/src/EditorFeatures/CSharp/GoToBase/CSharpGoToBaseService.cs b/src/EditorFeatures/CSharp/GoToBase/CSharpGoToBaseService.cs index 18a2f218ea74f..2a27d699a995b 100644 --- a/src/EditorFeatures/CSharp/GoToBase/CSharpGoToBaseService.cs +++ b/src/EditorFeatures/CSharp/GoToBase/CSharpGoToBaseService.cs @@ -6,10 +6,10 @@ using System; using System.Composition; -using Microsoft.CodeAnalysis.Editor.GoToBase; +using Microsoft.CodeAnalysis.GoToBase; using Microsoft.CodeAnalysis.Host.Mef; -namespace Microsoft.CodeAnalysis.Editor.CSharp.GoToBase +namespace Microsoft.CodeAnalysis.CSharp.GoToBase { [ExportLanguageService(typeof(IGoToBaseService), LanguageNames.CSharp), Shared] internal class CSharpGoToBaseService : AbstractGoToBaseService diff --git a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs new file mode 100644 index 0000000000000..c50a8d6a1d503 --- /dev/null +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.Commanding; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.RawStringLiteral +{ + [Export(typeof(ICommandHandler))] + [ContentType(ContentTypeNames.CSharpContentType)] + [Name(nameof(RawStringLiteralCommandHandler))] + [Order(After = nameof(SplitStringLiteralCommandHandler))] + internal partial class RawStringLiteralCommandHandler + { + private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; + private readonly IGlobalOptionService _globalOptions; + private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public RawStringLiteralCommandHandler( + ITextUndoHistoryRegistry undoHistoryRegistry, + IGlobalOptionService globalOptions, + IEditorOperationsFactoryService editorOperationsFactoryService) + { + _undoHistoryRegistry = undoHistoryRegistry; + _globalOptions = globalOptions; + _editorOperationsFactoryService = editorOperationsFactoryService; + } + + 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 new file mode 100644 index 0000000000000..a9c515e5b7d86 --- /dev/null +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.cs @@ -0,0 +1,121 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Commanding; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.RawStringLiteral +{ + internal partial class RawStringLiteralCommandHandler : ICommandHandler + { + public CommandState GetCommandState(ReturnKeyCommandArgs args) + => CommandState.Unspecified; + + /// + /// Checks to see if the user is typing return in """$$""" and then properly indents the end + /// delimiter of the raw string literal. + /// + public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext context) + { + var textView = args.TextView; + var subjectBuffer = args.SubjectBuffer; + var spans = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer); + + if (spans.Count != 1) + return false; + + var span = spans.First(); + if (span.Length != 0) + return false; + + var caret = textView.GetCaretPoint(subjectBuffer); + if (caret == null) + return false; + + var position = caret.Value.Position; + var currentSnapshot = subjectBuffer.CurrentSnapshot; + if (position >= currentSnapshot.Length) + return false; + + if (currentSnapshot[position] != '"') + return false; + + var quotesBefore = 0; + var quotesAfter = 0; + + for (int i = position, n = currentSnapshot.Length; i < n; i++) + { + if (currentSnapshot[i] == '"') + quotesAfter++; + } + + for (var i = position - 1; i >= 0; i--) + { + if (currentSnapshot[i] == '"') + quotesBefore++; + } + + if (quotesAfter != quotesBefore) + return false; + + if (quotesAfter < 3) + return false; + + return SplitRawString(textView, subjectBuffer, span.Start.Position, CancellationToken.None); + } + + private bool SplitRawString(ITextView textView, ITextBuffer subjectBuffer, int position, CancellationToken cancellationToken) + { + var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return false; + + var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); + var token = root.FindToken(position); + if (token.Kind() is not (SyntaxKind.SingleLineRawStringLiteralToken or + SyntaxKind.MultiLineRawStringLiteralToken or + SyntaxKind.InterpolatedSingleLineRawStringStartToken or + SyntaxKind.InterpolatedMultiLineRawStringStartToken)) + { + return false; + } + + var indentation = token.GetPreferredIndentation(document, cancellationToken); + + var newLine = document.Project.Solution.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); + + using var transaction = CaretPreservingEditTransaction.TryCreate( + CSharpEditorResources.Split_string, textView, _undoHistoryRegistry, _editorOperationsFactoryService); + + var edit = subjectBuffer.CreateEdit(); + + var sourceText = document.GetTextSynchronously(cancellationToken); + var textToInsert = $"{newLine}{newLine}{indentation}"; + + // apply the change: + edit.Insert(position, textToInsert); + var snapshot = edit.Apply(); + + // move caret: + var lineInNewSnapshot = snapshot.GetLineFromPosition(position); + var nextLine = snapshot.GetLineFromLineNumber(lineInNewSnapshot.LineNumber + 1); + textView.Caret.MoveTo(new VirtualSnapshotPoint(nextLine, indentation.Length)); + + transaction?.Complete(); + return true; + } + } +} diff --git a/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_TypeChar.cs b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_TypeChar.cs new file mode 100644 index 0000000000000..819d10551e8cc --- /dev/null +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_TypeChar.cs @@ -0,0 +1,238 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Commanding; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.RawStringLiteral +{ + internal partial class RawStringLiteralCommandHandler : IChainedCommandHandler + { + public CommandState GetCommandState(TypeCharCommandArgs args, Func nextCommandHandler) + => nextCommandHandler(); + + public void ExecuteCommand(TypeCharCommandArgs args, Action nextCommandHandler, CommandExecutionContext context) + { + if (!ExecuteCommandWorker(args, nextCommandHandler)) + nextCommandHandler(); + } + + private bool ExecuteCommandWorker(TypeCharCommandArgs args, Action nextCommandHandler) + { + if (args.TypedChar != '"') + return false; + + var textView = args.TextView; + var subjectBuffer = args.SubjectBuffer; + var spans = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer); + + if (spans.Count != 1) + return false; + + var span = spans.First(); + if (span.Length != 0) + return false; + + var caret = textView.GetCaretPoint(subjectBuffer); + if (caret == null) + return false; + + var cancellationToken = CancellationToken.None; + var textChangeOpt = + TryGenerateInitialEmptyRawString(caret.Value, cancellationToken) ?? + TryGrowInitialEmptyRawString(caret.Value, cancellationToken) ?? + TryGrowRawStringDelimeters(caret.Value, cancellationToken); + + if (textChangeOpt is not TextChange textChange) + return false; + + // Looks good. First, let the quote get added by the normal type char handlers. Then make our text change. + // We do this in two steps so that undo can work properly. + nextCommandHandler(); + + using var transaction = CaretPreservingEditTransaction.TryCreate( + CSharpEditorResources.Grow_raw_string, textView, _undoHistoryRegistry, _editorOperationsFactoryService); + + var edit = subjectBuffer.CreateEdit(); + edit.Insert(textChange.Span.Start, textChange.NewText); + edit.Apply(); + + // ensure the caret is placed after where the original quote got added. + textView.Caret.MoveTo(new SnapshotPoint(subjectBuffer.CurrentSnapshot, caret.Value.Position + 1)); + + transaction?.Complete(); + return true; + } + + /// + /// When typing " given a normal string like ""$$, then update the text to be """$$""". + /// Note that this puts the user in the position where TryGrowInitialEmptyRawString can now take effect. + /// + private static TextChange? TryGenerateInitialEmptyRawString( + SnapshotPoint caret, + CancellationToken cancellationToken) + { + var snapshot = caret.Snapshot; + var position = caret.Position; + + // if we have ""$$" then typing `"` here should not be handled by this path but by TryGrowInitialEmptyRawString + if (position + 1 < snapshot.Length && snapshot[position + 1] == '"') + return null; + + var start = position; + while (start - 1 >= 0 && snapshot[start - 1] == '"') + start--; + + // must have exactly `""` + if (position - start != 2) + return null; + + if (start - 1 >= 0 && snapshot[start - 1] == '$') + start--; + + // hitting `"` after `@""` shouldn't do anything + if (start - 1 >= 0 && snapshot[start - 1] == '@') + return null; + + var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return null; + + var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); + var token = root.FindToken(start); + if (token.SpanStart != start) + return null; + + if (token.Kind() is not SyntaxKind.StringLiteralToken and not SyntaxKind.InterpolatedStringStartToken) + return null; + + return new TextChange(new TextSpan(position + 1, 0), "\"\"\""); + } + + /// + /// When typing " given a raw string like """$$""" (or a similar multiline form), then update the + /// text to be: """"$$"""". i.e. grow both the start and end delimiters to keep the string properly + /// balanced. This differs from TryGrowRawStringDelimeters in that the language will consider that initial + /// """""" text to be a single delimeter, while we want to treat it as two. + /// + private static TextChange? TryGrowInitialEmptyRawString( + SnapshotPoint caret, + CancellationToken cancellationToken) + { + var snapshot = caret.Snapshot; + var position = caret.Position; + + var start = position; + while (start - 1 >= 0 && snapshot[start - 1] == '"') + start--; + + var end = position; + while (end < snapshot.Length && snapshot[end] == '"') + end++; + + // Have to have an even number of quotes. + var quoteLength = end - start; + if (quoteLength % 2 == 1) + return null; + + // User position must be halfway through the quotes. + if (position != (start + quoteLength / 2)) + return null; + + // have to at least have `"""$$"""` + if (quoteLength < 6) + return null; + + while (start - 1 >= 0 && snapshot[start - 1] == '$') + start--; + + var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return null; + + var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); + var token = root.FindToken(start); + if (token.SpanStart != start) + return null; + + if (token.Kind() is not (SyntaxKind.SingleLineRawStringLiteralToken or + SyntaxKind.MultiLineRawStringLiteralToken or + SyntaxKind.InterpolatedSingleLineRawStringStartToken or + SyntaxKind.InterpolatedMultiLineRawStringStartToken)) + { + return null; + } + + return new TextChange(new TextSpan(position + 1, 0), "\""); + } + + /// + /// When typing " given a raw string like """$$ goo bar """ (or a similar multiline form), then + /// update the text to be: """" goo bar """". i.e. grow both the start and end delimiters to keep the + /// string properly balanced. + /// + private static TextChange? TryGrowRawStringDelimeters( + SnapshotPoint caret, + CancellationToken cancellationToken) + { + var snapshot = caret.Snapshot; + var position = caret.Position; + + // if we have """$$" then typing `"` here should not grow the start/end quotes. we only want to grow them + // if the user is at the end of the start delimeter. + if (position < snapshot.Length && snapshot[position] == '"') + return null; + + var start = position; + while (start - 1 >= 0 && snapshot[start - 1] == '"') + start--; + + // must have at least three quotes for this to be a raw string + var quoteCount = position - start; + if (quoteCount < 3) + return null; + + while (start - 1 >= 0 && snapshot[start - 1] == '$') + start--; + + var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return null; + + var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); + var token = root.FindToken(start); + if (token.SpanStart != start) + return null; + + if (token.Span.Length < (2 * quoteCount)) + return null; + + if (token.Kind() is SyntaxKind.InterpolatedSingleLineRawStringStartToken or SyntaxKind.InterpolatedMultiLineRawStringStartToken) + { + var interpolatedString = (InterpolatedStringExpressionSyntax)token.GetRequiredParent(); + var endToken = interpolatedString.StringEndToken; + if (!endToken.Text.EndsWith(new string('"', quoteCount))) + return null; + } + else if (token.Kind() is SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken) + { + if (!token.Text.EndsWith(new string('"', quoteCount))) + return null; + } + + return new TextChange(new TextSpan(token.GetRequiredParent().Span.End, 0), "\""); + } + } +} diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf index 799cfcbd6b02f..c6c02c2ba3157 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf @@ -62,6 +62,11 @@ Generovat odběr událostí + + Grow raw string + Grow raw string + + Load from: '{0}' Načíst z {0} @@ -97,6 +102,11 @@ Chytré odsazování + + Split raw string + Split raw string + + Split string Rozdělit řetězec diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf index 467b6f0ba204a..239ec53d7abbb 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf @@ -62,6 +62,11 @@ Ereignisabonnement generieren + + Grow raw string + Grow raw string + + Load from: '{0}' Laden von: {0} @@ -97,6 +102,11 @@ Intelligenter Einzug + + Split raw string + Split raw string + + Split string Zeichenfolge teilen diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf index cbdac0f5d7ff2..f5357d0c76e28 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf @@ -62,6 +62,11 @@ Generar suscripción de eventos + + Grow raw string + Grow raw string + + Load from: '{0}' Cargar desde: "{0}" @@ -97,6 +102,11 @@ Sangría inteligente + + Split raw string + Split raw string + + Split string Dividir cadena diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf index 8f949734a99e4..dcb11a87b0ec4 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf @@ -62,6 +62,11 @@ Générer un abonnement à des événements + + Grow raw string + Grow raw string + + Load from: '{0}' Charger à partir de : '{0}' @@ -97,6 +102,11 @@ Retrait intelligent + + Split raw string + Split raw string + + Split string Fractionner la chaîne diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf index 7f468a5ea87b4..d0ef542df8bf4 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf @@ -62,6 +62,11 @@ Genera sottoscrizione di eventi + + Grow raw string + Grow raw string + + Load from: '{0}' Carica da: '{0}' @@ -97,6 +102,11 @@ Rientro automatico + + Split raw string + Split raw string + + Split string Dividi stringa diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf index ba142736d3e0d..53115b8855dd6 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf @@ -62,6 +62,11 @@ イベント サブスクリプションの生成 + + Grow raw string + Grow raw string + + Load from: '{0}' 読み込み元: '{0}' @@ -97,6 +102,11 @@ スマート インデント + + Split raw string + Split raw string + + Split string 文字列を分割します diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf index 7f49ed1c54b8a..ac4798428a5d8 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf @@ -62,6 +62,11 @@ 이벤트 구독 생성 + + Grow raw string + Grow raw string + + Load from: '{0}' 로드 위치: '{0}' @@ -97,6 +102,11 @@ 스마트 들여쓰기 + + Split raw string + Split raw string + + Split string 문자열 분할 diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf index 9f4fe6adb6b02..dbde5972370b6 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf @@ -62,6 +62,11 @@ Generuj subskrypcję zdarzenia + + Grow raw string + Grow raw string + + Load from: '{0}' Załaduj z: „{0}” @@ -97,6 +102,11 @@ Inteligentne tworzenie wcięć + + Split raw string + Split raw string + + Split string Rozdziel ciąg diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf index cd447bbfe530a..ca9a722ddf6a7 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf @@ -62,6 +62,11 @@ Gerar Assinatura de Evento + + Grow raw string + Grow raw string + + Load from: '{0}' Carregar de: '{0}' @@ -97,6 +102,11 @@ Recuo Inteligente + + Split raw string + Split raw string + + Split string Dividir cadeia de caracteres diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf index 63aea0788e038..f5124d9b475f4 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf @@ -62,6 +62,11 @@ Создать подписку на события + + Grow raw string + Grow raw string + + Load from: '{0}' Загрузить из: "{0}" @@ -97,6 +102,11 @@ Интеллектуальные отступы + + Split raw string + Split raw string + + Split string Разделить строку diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf index 04edf38859f66..2ddd35b87a300 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf @@ -62,6 +62,11 @@ Olay Aboneliği Oluştur + + Grow raw string + Grow raw string + + Load from: '{0}' Şuradan yükle: '{0}' @@ -97,6 +102,11 @@ Akıllı Girintileme + + Split raw string + Split raw string + + Split string Dizeyi böl diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf index 69abe07938eae..56989e4e1af7c 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf @@ -62,6 +62,11 @@ 生成事件订阅 + + Grow raw string + Grow raw string + + Load from: '{0}' 从以下位置加载: "{0}" @@ -97,6 +102,11 @@ 智能缩进 + + Split raw string + Split raw string + + Split string 拆分字符串 diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf index 6e1b43000c797..6836dd210095b 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf @@ -62,6 +62,11 @@ 產生事件訂閱 + + Grow raw string + Grow raw string + + Load from: '{0}' 載入來源: '{0}' @@ -97,6 +102,11 @@ 智慧縮排 + + Split raw string + Split raw string + + Split string 分割字串 diff --git a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs index 1a163db1b3ff6..899397848d526 100644 --- a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs +++ b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.AddImport; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.SymbolSearch; @@ -35,9 +36,8 @@ public class AddUsingNuGetTests : AbstractAddUsingTests protected override void InitializeWorkspace(TestWorkspace workspace, TestParameters parameters) { - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages, LanguageNames.CSharp, true) - .WithChangedOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.CSharp, true))); + workspace.GlobalOptions.SetGlobalOption(new OptionKey(SymbolSearchOptionsStorage.SearchNuGetPackages, LanguageNames.CSharp), true); + workspace.GlobalOptions.SetGlobalOption(new OptionKey(SymbolSearchOptionsStorage.SearchReferenceAssemblies, LanguageNames.CSharp), true); } internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer( diff --git a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs index b880fd532cebf..8139305e4ba92 100644 --- a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs +++ b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -6503,7 +6504,7 @@ static void Main(string[] args) [WorkItem(1266354, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1266354")] public async Task TestAddUsingsEditorBrowsableAdvancedDifferentProjectOptionOff(TestHost testHost) { - const string InitialWorkspace = @" + var initialWorkspace = @" @@ -6529,8 +6530,8 @@ static void Main(string[] args) "; - await TestMissingAsync(InitialWorkspace, new TestParameters( - options: Option(CompletionOptions.Metadata.HideAdvancedMembers, true), + await TestMissingAsync(initialWorkspace, new TestParameters( + codeActionOptions: CodeActionOptions.Default with { HideAdvancedMembers = true }, testHost: testHost)); } } diff --git a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs index 09bc5ce37966a..d9a223fec282c 100644 --- a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs +++ b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticBraceCompletionTests.cs @@ -2,12 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Editor.UnitTests.AutomaticCompletion; @@ -15,11 +11,9 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; using static Microsoft.CodeAnalysis.BraceCompletion.AbstractBraceCompletionService; -using static Microsoft.CodeAnalysis.CSharp.BraceCompletion.CurlyBraceCompletionService; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.AutomaticCompletion { @@ -1125,8 +1119,8 @@ public void X() var optionSet = new Dictionary { - { new OptionKey2(BraceCompletionOptions.AutoFormattingOnCloseBrace, LanguageNames.CSharp), false }, - { new OptionKey2(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, LanguageNames.CSharp), false }, + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block } }; using var session = CreateSession(code, optionSet); Assert.NotNull(session); @@ -1155,7 +1149,7 @@ public class C1 var optionSet = new Dictionary { - { new OptionKey2(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None } + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None } }; using var session = CreateSession(code, optionSet); Assert.NotNull(session); @@ -1190,7 +1184,7 @@ public class C1 var optionSet = new Dictionary { - { new OptionKey2(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block } + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block } }; using var session = CreateSession(code, optionSet); Assert.NotNull(session); @@ -1233,7 +1227,7 @@ public class C1 var optionSet = new Dictionary { - { new OptionKey2(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block } + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Block } }; using var session = CreateSession(code, optionSet); Assert.NotNull(session); @@ -1348,7 +1342,322 @@ public void CurlyBraceFormatting_InsertsCorrectNewLine() CheckReturn(session.Session, 4, result: "class C\r{\r\r}"); } - internal static Holder CreateSession(string code, Dictionary optionSet = null) + [WorkItem(50275, "https://github.com/dotnet/roslyn/issues/50275")] + [WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void WithInitializer_Enter(bool bracesOnNewLine) + { + var code = @" +record R +{ + public void man(R r) + { + var r2 = r with $$ + } +}"; + var expected = bracesOnNewLine ? @" +record R +{ + public void man(R r) + { + var r2 = r with + { + + } + } +}" : @" +record R +{ + public void man(R r) + { + var r2 = r with { + + } + } +}"; + var optionSet = new Dictionary + { + { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, bracesOnNewLine } + }; + using var session = CreateSession(code, optionSet); + Assert.NotNull(session); + + CheckStart(session.Session); + CheckReturn(session.Session, 12, expected); + } + + [WorkItem(50275, "https://github.com/dotnet/roslyn/issues/50275")] + [WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void PropertyPatternClause_Enter(bool bracesOnNewLine) + { + var code = @" +class C +{ + public void man() + { + if (x is string $$ + } +}"; + + var expected = bracesOnNewLine ? @" +class C +{ + public void man() + { + if (x is string + { + + } + } +}" : @" +class C +{ + public void man() + { + if (x is string { + + } + } +}"; + var optionSet = new Dictionary + { + { CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, bracesOnNewLine } + }; + using var session = CreateSession(code, optionSet); + Assert.NotNull(session); + + CheckStart(session.Session); + CheckReturn(session.Session, bracesOnNewLine ? 16 : 12, expected); + } + + [WorkItem(50275, "https://github.com/dotnet/roslyn/issues/50275")] + [WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void Accessor_Enter(bool bracesOnNewLine) + { + var code = @" +class C +{ + public int I + { + get $$ + } +}"; + + var expected = bracesOnNewLine ? @" +class C +{ + public int I + { + get + { + + } + } +}" : @" +class C +{ + public int I + { + get { + + } + } +}"; + var optionSet = new Dictionary + { + { CSharpFormattingOptions2.NewLinesForBracesInAccessors, bracesOnNewLine } + }; + using var session = CreateSession(code, optionSet); + Assert.NotNull(session); + + CheckStart(session.Session); + CheckReturn(session.Session, 12, expected); + } + + [WorkItem(50275, "https://github.com/dotnet/roslyn/issues/50275")] + [WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void AnonymousMethod_Enter(bool bracesOnNewLine) + { + var code = @" +class C +{ + public void man() + { + Action a = delegate() $$ + } +}"; + + var expected = bracesOnNewLine ? @" +class C +{ + public void man() + { + Action a = delegate() + { + + } + } +}" : @" +class C +{ + public void man() + { + Action a = delegate() { + + } + } +}"; + var optionSet = new Dictionary + { + { CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods, bracesOnNewLine } + }; + using var session = CreateSession(code, optionSet); + Assert.NotNull(session); + + CheckStart(session.Session); + CheckReturn(session.Session, 12, expected); + } + + [WorkItem(50275, "https://github.com/dotnet/roslyn/issues/50275")] + [WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void AnonymousType_Enter(bool bracesOnNewLine) + { + var code = @" +class C +{ + public void man() + { + var x = new $$ + } +}"; + + var expected = bracesOnNewLine ? @" +class C +{ + public void man() + { + var x = new + { + + } + } +}" : @" +class C +{ + public void man() + { + var x = new { + + } + } +}"; + var optionSet = new Dictionary + { + { CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes, bracesOnNewLine } + }; + using var session = CreateSession(code, optionSet); + Assert.NotNull(session); + + CheckStart(session.Session); + CheckReturn(session.Session, 12, expected); + } + + [WorkItem(50275, "https://github.com/dotnet/roslyn/issues/50275")] + [WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void If_OpenBraceOnSameLine_Enter(bool bracesOnNewLine) + { + var code = @" +class C +{ + public void man() + { + if (true) $$ + } +}"; + + var expected = bracesOnNewLine ? @" +class C +{ + public void man() + { + if (true) + { + + } + } +}" : @" +class C +{ + public void man() + { + if (true) { + + } + } +}"; + + var optionSet = new Dictionary + { + { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, bracesOnNewLine } + }; + using var session = CreateSession(code, optionSet); + Assert.NotNull(session); + + CheckStart(session.Session); + CheckReturn(session.Session, 12, expected); + } + + [WorkItem(50275, "https://github.com/dotnet/roslyn/issues/50275")] + [WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void Else_OpenBraceOnSameLine_Enter(bool bracesOnNewLine) + { + var code = @" +class C +{ + public void man() + { + if (true) { + } + else $$ + } +}"; + + var expected = bracesOnNewLine ? @" +class C +{ + public void man() + { + if (true) { + } + else + { + + } + } +}" : @" +class C +{ + public void man() + { + if (true) { + } + else { + + } + } +}"; + + var optionSet = new Dictionary + { + { CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, bracesOnNewLine } + }; + using var session = CreateSession(code, optionSet); + Assert.NotNull(session); + + CheckStart(session.Session); + CheckReturn(session.Session, 12, expected); + } + + internal static Holder CreateSession(string code, Dictionary? optionSet = null) { return CreateSession( TestWorkspace.CreateCSharp(code), diff --git a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticLiteralCompletionTests.cs b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticLiteralCompletionTests.cs index add5b96e93c60..96c6f4b160add 100644 --- a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticLiteralCompletionTests.cs +++ b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticLiteralCompletionTests.cs @@ -80,7 +80,7 @@ void Method() }"; using var session = CreateSessionDoubleQuote(code); Assert.NotNull(session); - CheckStart(session.Session); + CheckStart(session.Session, expectValidSession: false); } [WpfFact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] diff --git a/src/EditorFeatures/CSharpTest/BraceHighlighting/BraceHighlightingTests.cs b/src/EditorFeatures/CSharpTest/BraceHighlighting/BraceHighlightingTests.cs index 755fbfc7a77a4..3416cb73fd1b0 100644 --- a/src/EditorFeatures/CSharpTest/BraceHighlighting/BraceHighlightingTests.cs +++ b/src/EditorFeatures/CSharpTest/BraceHighlighting/BraceHighlightingTests.cs @@ -446,5 +446,89 @@ void Goo() await TestBraceHighlightingAsync(input, swapAnglesWithBrackets: true); } + + [WpfFact, Trait(Traits.Feature, Traits.Features.BraceHighlighting)] + public async Task TestJsonBracket1() + { + var input = @" +class C +{ + void Goo() + { + var r = /*lang=json*/ @""new Json[|$$(|]1, 2, 3[|)|]""; + } +}"; + await TestBraceHighlightingAsync(input); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.BraceHighlighting)] + public async Task TestJsonBracket2() + { + var input = @" +class C +{ + void Goo() + { + var r = /*lang=json*/ @""new Json[|(|]1, 2, 3[|)|]$$""; + } +}"; + await TestBraceHighlightingAsync(input); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.BraceHighlighting)] + public async Task TestJsonBracket_RawStrings() + { + var input = @" +class C +{ + void Goo() + { + var r = /*lang=json*/ """"""new Json[|$$(|]1, 2, 3[|)|]""""""; + } +}"; + await TestBraceHighlightingAsync(input); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.BraceHighlighting)] + public async Task TestUnmatchedJsonBracket1() + { + var input = @" +class C +{ + void Goo() + { + var r = /*lang=json*/ @""new Json$$(1, 2, 3""; + } +}"; + await TestBraceHighlightingAsync(input); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.BraceHighlighting)] + public async Task TestJsonBracket_NoComment_NotLikelyJson() + { + var input = @" +class C +{ + void Goo() + { + var r = @""$$[ 1, 2, 3 ]""; + } +}"; + await TestBraceHighlightingAsync(input); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.BraceHighlighting)] + public async Task TestJsonBracket_NoComment_LikelyJson() + { + var input = @" +class C +{ + void Goo() + { + var r = @""[ { prop: 0 }, new Json[|$$(|]1, 2, 3[|)|], 3 ]""; + } +}"; + await TestBraceHighlightingAsync(input); + } } } diff --git a/src/EditorFeatures/CSharpTest/Classification/AbstractCSharpClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/AbstractCSharpClassifierTests.cs index a7db03e23e6c9..a0784cae39d26 100644 --- a/src/EditorFeatures/CSharpTest/Classification/AbstractCSharpClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/AbstractCSharpClassifierTests.cs @@ -18,7 +18,7 @@ public abstract class AbstractCSharpClassifierTests : AbstractClassifierTests protected static TestWorkspace CreateWorkspace(string code, ParseOptions options, TestHost testHost) { var composition = EditorTestCompositions.EditorFeatures.WithTestHostParts(testHost); - return TestWorkspace.CreateCSharp(code, parseOptions: options, composition: composition); + return TestWorkspace.CreateCSharp(code, parseOptions: options, composition: composition, isMarkup: false); } protected override async Task DefaultTestAsync(string code, string allCode, TestHost testHost, FormattedClassification[] expected) diff --git a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs index e036949a7be05..2e7e57b3eaf49 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities.EmbeddedLanguages; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -32,10 +33,10 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Classification [Trait(Traits.Feature, Traits.Features.Classification)] public class SemanticClassifierTests : AbstractCSharpClassifierTests { - protected override async Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions options, TestHost testHost) + protected override async Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions? options, TestHost testHost) { using var workspace = CreateWorkspace(code, options, testHost); - var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); + var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id); return await GetSemanticClassificationsAsync(document, span); } @@ -2970,7 +2971,6 @@ await TestAsync( class Program { - void Goo() { var r = new Regex(@""$(\a\t\u0020)|[^\p{Lu}-a\w\sa-z-[m-p]]+?(?#comment)|(\b\G\z)|(?sub){0,5}?^""); @@ -3054,7 +3054,6 @@ await TestAsync( class Program { - void Goo() { // language=regex @@ -3423,6 +3422,62 @@ class Program Regex.Grouping(")")); } + [Theory] + [CombinatorialData] + public async Task TestRegexSingleLineRawStringLiteral(TestHost testHost) + { + await TestAsync( +@" +using System.Text.RegularExpressions; + +class Program +{ + void Goo() + { + var r = /* lang=regex */ """"""$\a(?#comment)""""""; + } +}", +testHost, Namespace("System"), +Namespace("Text"), +Namespace("RegularExpressions"), +Keyword("var"), +Regex.Anchor("$"), +Regex.OtherEscape("\\"), +Regex.OtherEscape("a"), +Regex.Comment("(?#comment)")); + } + + [Theory] + [CombinatorialData] + public async Task TestRegexMultiLineRawStringLiteral(TestHost testHost) + { + await TestAsync( +@" +using System.Text.RegularExpressions; + +class Program +{ + void Goo() + { + var r = /* lang=regex */ """""" + $\a(?#comment) + """"""; + } +}", +testHost, Namespace("System"), +Namespace("Text"), +Namespace("RegularExpressions"), +Keyword("var"), +Regex.Text(@" + "), +Regex.Anchor("$"), +Regex.OtherEscape("\\"), +Regex.OtherEscape("a"), +Regex.Comment("(?#comment)"), +Regex.Text(@" + ")); + } + [Theory, WorkItem(47079, "https://github.com/dotnet/roslyn/issues/47079")] [CombinatorialData] public async Task TestRegexWithSpecialCSharpCharLiterals(TestHost testHost) @@ -3447,6 +3502,148 @@ class Program Regex.Anchor("$")); } + [Theory] + [CombinatorialData] + public async Task TestRegexOnApiWithStringSyntaxAttribute_Field(TestHost testHost) + { + await TestAsync( +@" +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; + +class Program +{ + [StringSyntax(StringSyntaxAttribute.Regex)] + private string field; + + void Goo() + { + [|this.field = @""$\a(?#comment)"";|] + } +}" + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, +testHost, +Field("field"), +Regex.Anchor("$"), +Regex.OtherEscape("\\"), +Regex.OtherEscape("a"), +Regex.Comment("(?#comment)")); + } + + [Theory] + [CombinatorialData] + public async Task TestRegexOnApiWithStringSyntaxAttribute_Property(TestHost testHost) + { + await TestAsync( +@" +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; + +class Program +{ + [StringSyntax(StringSyntaxAttribute.Regex)] + private string Prop { get; set; } + + void Goo() + { + [|this.Prop = @""$\a(?#comment)"";|] + } +}" + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, +testHost, +Property("Prop"), +Regex.Anchor("$"), +Regex.OtherEscape("\\"), +Regex.OtherEscape("a"), +Regex.Comment("(?#comment)")); + } + + [Theory] + [CombinatorialData] + public async Task TestRegexOnApiWithStringSyntaxAttribute_Argument(TestHost testHost) + { + await TestAsync( +@" +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; + +class Program +{ + private void M([StringSyntax(StringSyntaxAttribute.Regex)] string p) + { + } + + void Goo() + { + [|M(@""$\a(?#comment)"");|] + } +}" + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, +testHost, +Method("M"), +Regex.Anchor("$"), +Regex.OtherEscape("\\"), +Regex.OtherEscape("a"), +Regex.Comment("(?#comment)")); + } + + [Theory] + [CombinatorialData] + public async Task TestRegexOnApiWithStringSyntaxAttribute_Argument_Options(TestHost testHost) + { + await TestAsync( +@" +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; + +class Program +{ + private void M([StringSyntax(StringSyntaxAttribute.Regex)] string p, RegexOptions options) + { + } + + void Goo() + { + [|M(@""$\a(?#comment) # is end of line comment"", RegexOptions.IgnorePatternWhitespace);|] + } +}" + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, +testHost, +Method("M"), +Regex.Anchor("$"), +Regex.OtherEscape("\\"), +Regex.OtherEscape("a"), +Regex.Comment("(?#comment)"), +Regex.Comment("# is end of line comment"), +Enum("RegexOptions"), +EnumMember("IgnorePatternWhitespace")); + } + + [Theory] + [CombinatorialData] + public async Task TestRegexOnApiWithStringSyntaxAttribute_Attribute(TestHost testHost) + { + await TestAsync( +@" +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; + +[AttributeUsage(AttributeTargets.Field)] +class RegexTestAttribute : Attribute +{ + public RegexTestAttribute([StringSyntax(StringSyntaxAttribute.Regex)] string value) { } +} + +class Program +{ + [|[RegexTest(@""$\a(?#comment)"")]|] + private string field; +}" + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, +testHost, +Class("RegexTest"), +Regex.Anchor("$"), +Regex.OtherEscape("\\"), +Regex.OtherEscape("a"), +Regex.Comment("(?#comment)")); + } + [Theory] [CombinatorialData] public async Task TestIncompleteRegexLeadingToStringInsideSkippedTokensInsideADirective(TestHost testHost) @@ -3477,6 +3674,262 @@ void M() Class("Regex")); } + [Theory] + [CombinatorialData] + public async Task TestJson1(TestHost testHost) + { + await TestAsync( +@" +class Program +{ + void Goo() + { + // lang=json + var r = @""[/*comment*/{ 'goo': 0, bar: -Infinity, """"baz"""": true }, new Date(), text, 'str'] // comment""; + } +}", +testHost, +Keyword("var"), +Json.Array("["), +Json.Comment("/*comment*/"), +Json.Object("{"), +Json.PropertyName("'goo'"), +Json.Punctuation(":"), +Json.Number("0"), +Json.PropertyName("bar"), +Json.Punctuation(":"), +Json.Operator("-"), +Json.Keyword("Infinity"), +Json.PropertyName(@"""""baz"""""), +Json.Punctuation(":"), +Json.Keyword("true"), +Json.Object("}"), +Json.Punctuation(","), +Json.Keyword("new"), +Json.ConstructorName("Date"), +Json.Punctuation("("), +Json.Punctuation(")"), +Json.Punctuation(","), +Json.Text("text"), +Json.Punctuation(","), +Json.String("'str'"), +Json.Array("]"), +Json.Comment("// comment")); + } + + [Theory] + [CombinatorialData] + public async Task TestJson_RawString(TestHost testHost) + { + await TestAsync( +@" +class Program +{ + void Goo() + { + // lang=json + var r = """"""[/*comment*/{ 'goo': 0 }]""""""; + } +}", +testHost, +Keyword("var"), +Json.Array("["), +Json.Comment("/*comment*/"), +Json.Object("{"), +Json.PropertyName("'goo'"), +Json.Punctuation(":"), +Json.Number("0"), +Json.Object("}"), +Json.Array("]")); + } + + [Theory] + [CombinatorialData] + public async Task TestMultiLineJson1(TestHost testHost) + { + await TestAsync( +@" +class Program +{ + void Goo() + { + // lang=json + var r = @""[ + /*comment*/ + { + 'goo': 0, + bar: -Infinity, + """"baz"""": true, + 0: null + }, + new Date(), + text, + 'str'] // comment""; + } +}", +testHost, +Keyword("var"), +Json.Array("["), +Json.Comment("/*comment*/"), +Json.Object("{"), +Json.PropertyName("'goo'"), +Json.Punctuation(":"), +Json.Number("0"), +Json.PropertyName("bar"), +Json.Punctuation(":"), +Json.Operator("-"), +Json.Keyword("Infinity"), +Json.PropertyName(@"""""baz"""""), +Json.Punctuation(":"), +Json.Keyword("true"), +Json.PropertyName("0"), +Json.Punctuation(":"), +Json.Keyword("null"), +Json.Object("}"), +Json.Punctuation(","), +Json.Keyword("new"), +Json.ConstructorName("Date"), +Json.Punctuation("("), +Json.Punctuation(")"), +Json.Punctuation(","), +Json.Text("text"), +Json.Punctuation(","), +Json.String("'str'"), +Json.Array("]"), +Json.Comment("// comment")); + } + + [Theory] + [CombinatorialData] + public async Task TestJson_NoComment_NotLikelyJson(TestHost testHost) + { + var input = @" +class C +{ + void Goo() + { + var r = @""[1, 2, 3]""; + } +}"; + await TestAsync(input, +testHost, +Keyword("var")); + } + + [Theory] + [CombinatorialData] + public async Task TestJson_NoComment_LikelyJson(TestHost testHost) + { + var input = @" +class C +{ + void Goo() + { + var r = @""[1, { prop: 0 }, 3]""; + } +}"; + await TestAsync(input, +testHost, +Keyword("var"), +Json.Array("["), +Json.Number("1"), +Json.Punctuation(","), +Json.Object("{"), +Json.PropertyName("prop"), +Json.Punctuation(":"), +Json.Number("0"), +Json.Object("}"), +Json.Punctuation(","), +Json.Number("3"), +Json.Array("]")); + } + + [Theory] + [CombinatorialData] + public async Task TestJsonOnApiWithStringSyntaxAttribute_Field(TestHost testHost) + { + await TestAsync( +@" +using System.Diagnostics.CodeAnalysis; + +class Program +{ + [StringSyntax(StringSyntaxAttribute.Json)] + private string field; + void Goo() + { + [|this.field = @""[{ 'goo': 0}]"";|] + } +}" + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, +testHost, +Field("field"), +Json.Array("["), +Json.Object("{"), +Json.PropertyName("'goo'"), +Json.Punctuation(":"), +Json.Number("0"), +Json.Object("}"), +Json.Array("]")); + } + + [Theory] + [CombinatorialData] + public async Task TestJsonOnApiWithStringSyntaxAttribute_Property(TestHost testHost) + { + await TestAsync( +@" +using System.Diagnostics.CodeAnalysis; + +class Program +{ + [StringSyntax(StringSyntaxAttribute.Json)] + private string Prop { get; set; } + void Goo() + { + [|this.Prop = @""[{ 'goo': 0}]"";|] + } +}" + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, +testHost, +Property("Prop"), +Json.Array("["), +Json.Object("{"), +Json.PropertyName("'goo'"), +Json.Punctuation(":"), +Json.Number("0"), +Json.Object("}"), +Json.Array("]")); + } + + [Theory] + [CombinatorialData] + public async Task TestJsonOnApiWithStringSyntaxAttribute_Argument(TestHost testHost) + { + await TestAsync( +@" +using System.Diagnostics.CodeAnalysis; + +class Program +{ + private void M([StringSyntax(StringSyntaxAttribute.Json)] string p) + { + } + + void Goo() + { + [|M(@""[{ 'goo': 0}]"");|] + } +}" + EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp, +testHost, +Method("M"), +Json.Array("["), +Json.Object("{"), +Json.PropertyName("'goo'"), +Json.Punctuation(":"), +Json.Number("0"), +Json.Object("}"), +Json.Array("]")); + } + [Theory] [CombinatorialData] public async Task TestUnmanagedConstraint_LocalFunction_Keyword(TestHost testHost) diff --git a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs index fa671a21b1114..fd5fcbb83f2a5 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Classification { public partial class SyntacticClassifierTests : AbstractCSharpClassifierTests { - protected override async Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions options, TestHost testHost) + protected override async Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions? options, TestHost testHost) { using var workspace = CreateWorkspace(code, options, testHost); var document = workspace.CurrentSolution.Projects.First().Documents.First(); @@ -5707,5 +5707,167 @@ await TestAsync(code, Punctuation.CloseCurly, Punctuation.CloseCurly); } + + [Theory] + [CombinatorialData] + public async Task TestRawStringLiteral(TestHost testHost) + { + var code = @" +class C +{ + public static void M(int x) + { + var s = """"""Hello world""""""; + } +}"; + + await TestAsync(code, + testHost, + Keyword("class"), + Class("C"), + Punctuation.OpenCurly, + Keyword("public"), + Keyword("static"), + Keyword("void"), + Method("M"), + Static("M"), + Punctuation.OpenParen, + Keyword("int"), + Parameter("x"), + Punctuation.CloseParen, + Punctuation.OpenCurly, + Keyword("var"), + Local("s"), + Operators.Equals, + String("\"\"\"Hello world\"\"\""), + Punctuation.Semicolon, + Punctuation.CloseCurly, + Punctuation.CloseCurly); + } + + [Theory] + [CombinatorialData] + public async Task TestRawStringLiteralInterpolation1(TestHost testHost) + { + var code = @" +class C +{ + public static void M(int x) + { + var s = $""""""{x}""""""; + } +}"; + + await TestAsync(code, + testHost, + Keyword("class"), + Class("C"), + Punctuation.OpenCurly, + Keyword("public"), + Keyword("static"), + Keyword("void"), + Method("M"), + Static("M"), + Punctuation.OpenParen, + Keyword("int"), + Parameter("x"), + Punctuation.CloseParen, + Punctuation.OpenCurly, + Keyword("var"), + Local("s"), + Operators.Equals, + String("$\"\"\""), + Punctuation.OpenCurly, + Identifier("x"), + Punctuation.CloseCurly, + String("\"\"\""), + Punctuation.Semicolon, + Punctuation.CloseCurly, + Punctuation.CloseCurly); + } + + [Theory] + [CombinatorialData] + public async Task TestRawStringLiteralInterpolation2(TestHost testHost) + { + var code = @" +class C +{ + public static void M(int x) + { + var s = $$""""""{{x}}""""""; + } +}"; + + await TestAsync(code, + testHost, + Keyword("class"), + Class("C"), + Punctuation.OpenCurly, + Keyword("public"), + Keyword("static"), + Keyword("void"), + Method("M"), + Static("M"), + Punctuation.OpenParen, + Keyword("int"), + Parameter("x"), + Punctuation.CloseParen, + Punctuation.OpenCurly, + Keyword("var"), + Local("s"), + Operators.Equals, + String("$$\"\"\""), + PunctuationText("{{"), + Identifier("x"), + PunctuationText("}}"), + String("\"\"\""), + Punctuation.Semicolon, + Punctuation.CloseCurly, + Punctuation.CloseCurly); + } + + [Theory] + [CombinatorialData] + public async Task TestRawStringLiteralInterpolation3(TestHost testHost) + { + var code = @" +class C +{ + public static void M(int x) + { + var s = $$""""""{{{x}}}""""""; + } +}"; + + await TestAsync(code, + testHost, + Keyword("class"), + Class("C"), + Punctuation.OpenCurly, + Keyword("public"), + Keyword("static"), + Keyword("void"), + Method("M"), + Static("M"), + Punctuation.OpenParen, + Keyword("int"), + Parameter("x"), + Punctuation.CloseParen, + Punctuation.OpenCurly, + Keyword("var"), + Local("s"), + Operators.Equals, + String("$$\"\"\""), + String("{"), + PunctuationText("{{"), + Identifier("x"), + PunctuationText("}}"), + String("}"), + String("\"\"\""), + Punctuation.Semicolon, + Punctuation.CloseCurly, + Punctuation.CloseCurly); + } } } diff --git a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs index 19bb5e55fb279..50199eed066c3 100644 --- a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Remote.Testing; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; @@ -19,10 +20,10 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Classification [Trait(Traits.Feature, Traits.Features.Classification)] public partial class TotalClassifierTests : AbstractCSharpClassifierTests { - protected override async Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions options, TestHost testHost) + protected override async Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions? options, TestHost testHost) { using var workspace = CreateWorkspace(code, options, testHost); - var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); + var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id); return await GetAllClassificationsAsync(document, span); } @@ -2189,5 +2190,55 @@ public async Task TestStringEscape(TestHost testHost) Verbatim("\""), Punctuation.Semicolon); } + + [Theory] + [CombinatorialData] + [WorkItem(55313, "https://github.com/dotnet/roslyn/issues/55313")] + public async Task TestStaticConstructorClass(TestHost testHost) + { + await TestAsync( +@" +class C +{ + static C() { } +}", + testHost, +Keyword("class"), +Class("C"), +Punctuation.OpenCurly, +Keyword("static"), +Class("C"), +Static("C"), +Punctuation.OpenParen, +Punctuation.CloseParen, +Punctuation.OpenCurly, +Punctuation.CloseCurly, +Punctuation.CloseCurly); + } + + [Theory] + [CombinatorialData] + [WorkItem(55313, "https://github.com/dotnet/roslyn/issues/55313")] + public async Task TestStaticConstructorInterface(TestHost testHost) + { + await TestAsync( +@" +interface C +{ + static C() { } +}", + testHost, +Keyword("interface"), +Interface("C"), +Punctuation.OpenCurly, +Keyword("static"), +Interface("C"), +Static("C"), +Punctuation.OpenParen, +Punctuation.CloseParen, +Punctuation.OpenCurly, +Punctuation.CloseCurly, +Punctuation.CloseCurly); + } } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs index 258e4eba49d4e..fab6019cea8a2 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/ExtractMethod/ExtractMethodTests.cs @@ -4617,5 +4617,31 @@ class Ignored2 { } CodeActionEquivalenceKey = nameof(FeaturesResources.Extract_method), }.RunAsync(); } + + [WorkItem(57428, "https://github.com/dotnet/roslyn/issues/57428")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractMethod)] + public async Task AttributeArgumentWithLambdaBody() + { + await TestInRegularAndScript1Async( +@"using System.Runtime.InteropServices; +class Program +{ + static void F([DefaultParameterValue(() => { return [|null|]; })] object obj) + { + } +}", +@"using System.Runtime.InteropServices; +class Program +{ + static void F([DefaultParameterValue(() => { return {|Rename:NewMethod|}(); })] object obj) + { + } + + private static object NewMethod() + { + return null; + } +}"); + } } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/IntroduceParameter/IntroduceParameterTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/IntroduceParameter/IntroduceParameterTests.cs index fc3e13daa81cd..05a41da7fe725 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/IntroduceParameter/IntroduceParameterTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/IntroduceParameter/IntroduceParameterTests.cs @@ -1932,5 +1932,62 @@ public Program(int x) "; await TestInRegularAndScriptAsync(code, expected, 0); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceParameter)] + public async Task TestIntroduceParameterOnParameter() + { + var code = +@" +using System; + +class Program +{ + public static void Main(string[] args) + { + Console.WriteLine([|args|]); + } +} +"; + + await TestMissingInRegularAndScriptAsync(code); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceParameter)] + public async Task TestIntroduceParameterOnExpressionContainingParameter() + { + var code = +@" +public class C +{ + public void M(string s) + { + localFunction(); + + void localFunction() + { + _ = [|s|].ToString(); + } + } +} +"; + + var expected = +@" +public class C +{ + public void M(string s) + { + localFunction(s); + + void localFunction(string s) + { + _ = {|Rename:s|}.ToString(); + } + } +} +"; + + await TestInRegularAndScriptAsync(code, expected, 0); + } } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/LambdaSimplifier/LambdaSimplifierTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/LambdaSimplifier/LambdaSimplifierTests.cs deleted file mode 100644 index 365d272454b37..0000000000000 --- a/src/EditorFeatures/CSharpTest/CodeActions/LambdaSimplifier/LambdaSimplifierTests.cs +++ /dev/null @@ -1,643 +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.CSharp.CodeRefactorings.LambdaSimplifier; -using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.LambdaSimplifier -{ - public class LambdaSimplifierTests : AbstractCSharpCodeActionTest - { - protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) - => new LambdaSimplifierCodeRefactoringProvider(); - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixAll1() - { - await TestInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar(s [||]=> Quux(s)); - } - - void Bar(Func f); - string Quux(int i); -}", -@"using System; - -class C -{ - void Goo() - { - Bar(Quux); - } - - void Bar(Func f); - string Quux(int i); -}", - index: 1); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixCoContravariance1() - { - await TestInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar(s [||]=> Quux(s)); - } - - void Bar(Func f); - string Quux(object o); -}", -@"using System; - -class C -{ - void Goo() - { - Bar(Quux); - } - - void Bar(Func f); - string Quux(object o); -}", - index: 1); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixCoContravariance2() - { - await TestInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar(s [||]=> Quux(s)); - } - - void Bar(Func f); - string Quux(object o); -}", -@"using System; - -class C -{ - void Goo() - { - Bar(Quux); - } - - void Bar(Func f); - string Quux(object o); -}", - index: 1); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixCoContravariance3() - { - await TestMissingInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar(s [||]=> Quux(s)); - } - - void Bar(Func f); - object Quux(object o); -}"); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixCoContravariance4() - { - await TestMissingInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar(s [||]=> Quux(s)); - } - - void Bar(Func f); - string Quux(string o); -}"); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixCoContravariance5() - { - await TestMissingInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar(s [||]=> Quux(s)); - } - - void Bar(Func f); - object Quux(string o); -}"); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixAll2() - { - await TestInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar((s1, s2) [||]=> Quux(s1, s2)); - } - - void Bar(Func f); - string Quux(int i, bool b); -}", -@"using System; - -class C -{ - void Goo() - { - Bar(Quux); - } - - void Bar(Func f); - string Quux(int i, bool b); -}", - index: 1); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixAll3() - { - await TestInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar((s1, s2) [||]=> { - return Quux(s1, s2); - }); - } - - void Bar(Func f); - string Quux(int i, bool b); -}", -@"using System; - -class C -{ - void Goo() - { - Bar(Quux); - } - - void Bar(Func f); - string Quux(int i, bool b); -}", - index: 1); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixAll4() - { - await TestInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar((s1, s2) [||]=> { - return this.Quux(s1, s2); - }); - } - - void Bar(Func f); - string Quux(int i, bool b); -}", -@"using System; - -class C -{ - void Goo() - { - Bar(this.Quux); - } - - void Bar(Func f); - string Quux(int i, bool b); -}", - index: 1); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestFixOneOrAll() - { - await TestInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar(s [||]=> Quux(s)); - Bar(s => Quux(s)); - } - - void Bar(Func f); - string Quux(int i); -}", -@"using System; - -class C -{ - void Goo() - { - Bar(Quux); - Bar(s => Quux(s)); - } - - void Bar(Func f); - string Quux(int i); -}", - index: 0); - - await TestInRegularAndScriptAsync( -@"using System; - -class C -{ - void Goo() - { - Bar(s [||]=> Quux(s)); - Bar(s => Quux(s)); - } - - void Bar(Func f); - string Quux(int i); -}", -@"using System; - -class C -{ - void Goo() - { - Bar(Quux); - Bar(Quux); - } - - void Bar(Func f); - string Quux(int i); -}", - index: 1); - } - - [WorkItem(542562, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542562")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestMissingOnAmbiguity1_CSharp7() - { - await TestMissingInRegularAndScriptAsync( -@"using System; - -class A -{ - static void Goo(T x) where T : class - { - } - - static void Bar(Action x) - { - } - - static void Bar(Action x) - { - } - - static void Main() - { - Bar(x [||]=> Goo(x)); - } -}", parameters: new TestParameters(TestOptions.Regular7)); - } - - [WorkItem(542562, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542562")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestMissingOnAmbiguity1() - { - var code = @" -using System; -class A -{ - static void Goo(T x) where T : class - { - } - - static void Bar(Action x) - { - } - - static void Bar(Action x) - { - } - - static void Main() - { - Bar(x [||]=> Goo(x)); - } -}"; - - var expected = @" -using System; -class A -{ - static void Goo(T x) where T : class - { - } - - static void Bar(Action x) - { - } - - static void Bar(Action x) - { - } - - static void Main() - { - Bar(Goo); - } -}"; - - await TestInRegularAndScriptAsync(code, expected, parseOptions: TestOptions.Regular7_3); - } - - [WorkItem(627092, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/627092")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestMissingOnLambdaWithDynamic_1() - { - await TestMissingInRegularAndScriptAsync( -@"using System; - -class Program -{ - static void Main() - { - C.InvokeGoo(); - } -} - -class C -{ - public static void InvokeGoo() - { - Action goo = (x, y) => [||]C.Goo(x, y); // Simplify lambda expression - goo(1, ""); - } - - static void Goo(object x, object y) - { - Console.WriteLine(""Goo(object x, object y)""); - } - - static void Goo(object x, T y) - { - Console.WriteLine(""Goo(object x, T y)""); - } -}"); - } - - [WorkItem(627092, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/627092")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestMissingOnLambdaWithDynamic_2() - { - await TestMissingInRegularAndScriptAsync( -@"using System; - -class Program -{ - static void Main() - { - C.InvokeGoo(); - } -} - -class Casd -{ - public static void InvokeGoo() - { - Action goo = x => [||]Casd.Goo(x); // Simplify lambda expression - goo(1, ""); - } - - private static void Goo(dynamic x) - { - throw new NotImplementedException(); - } - - static void Goo(object x, object y) - { - Console.WriteLine(""Goo(object x, object y)""); - } - - static void Goo(object x, T y) - { - Console.WriteLine(""Goo(object x, T y)""); - } -}"); - } - - [WorkItem(544625, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544625")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task ParenthesizeIfParseChanges() - { - var code = @" -using System; -class C -{ - static void M() - { - C x = new C(); - int y = 1; - Bar(() [||]=> { return Console.ReadLine(); } < x, y > (1 + 2)); - } - - static void Bar(object a, object b) { } - public static bool operator <(Func y, C x) { return true; } - public static bool operator >(Func y, C x) { return true; } -}"; - - var expected = @" -using System; -class C -{ - static void M() - { - C x = new C(); - int y = 1; - Bar((Console.ReadLine) < x, y > (1 + 2)); - } - - static void Bar(object a, object b) { } - public static bool operator <(Func y, C x) { return true; } - public static bool operator >(Func y, C x) { return true; } -}"; - - await TestInRegularAndScriptAsync(code, expected); - } - - [WorkItem(545856, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545856")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestWarningOnSideEffects() - { - await TestInRegularAndScriptAsync( -@"using System; - -class C -{ - void Main() - { - Func a = () [||]=> new C().ToString(); - } -}", -@"using System; - -class C -{ - void Main() - { - Func a = {|Warning:new C()|}.ToString; - } -}"); - } - - [WorkItem(545994, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545994")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestNonReturnBlockSyntax() - { - await TestInRegularAndScriptAsync( -@"using System; - -class Program -{ - static void Main() - { - Action a = [||]() => { - Console.WriteLine(); - }; - } -}", -@"using System; - -class Program -{ - static void Main() - { - Action a = Console.WriteLine; - } -}"); - } - - [WorkItem(35180, "https://github.com/dotnet/roslyn/issues/35180")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestMissingCaretPositionInside() - { - await TestMissingInRegularAndScriptAsync( -@"using System; - -class Program -{ - static void Main() - { - Action a = () => { - Console.[||]WriteLine(); - }; - } -}"); - } - - [WorkItem(35180, "https://github.com/dotnet/roslyn/issues/35180")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestCaretPositionBeforeBody() - { - await TestInRegularAndScriptAsync( -@"using System; - -class Program -{ - static void Main() - { - Action a = () => [||]Console.WriteLine(); - } -}", -@"using System; - -class Program -{ - static void Main() - { - Action a = Console.WriteLine; - } -}"); - } - - [WorkItem(35180, "https://github.com/dotnet/roslyn/issues/35180")] - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsLambdaSimplifier)] - public async Task TestCaretPosition() - { - await TestInRegularAndScriptAsync( -@"using System; - -class Program -{ - static void Main() - { - [|Action a = () => { - Console.WriteLine(); - };|] - } -}", -@"using System; - -class Program -{ - static void Main() - { - Action a = Console.WriteLine; - } -}"); - } - } -} diff --git a/src/EditorFeatures/CSharpTest/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsRefactoringTests.cs b/src/EditorFeatures/CSharpTest/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsRefactoringTests.cs index d72e97c3e8ab5..5eacb7a1a6708 100644 --- a/src/EditorFeatures/CSharpTest/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsRefactoringTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsRefactoringTests.cs @@ -17,11 +17,15 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.UseRec [Trait(Traits.Feature, Traits.Features.CodeActionsUseRecursivePatterns)] public class UseRecursivePatternsRefactoringTests { - private static Task VerifyAsync(string initialMarkup, string expectedMarkup, bool skipCodeActionValidation = false) + private static Task VerifyAsync( + string initialMarkup, + string expectedMarkup, + bool skipCodeActionValidation = false, + LanguageVersion languageVersion = LanguageVersion.CSharp9) { return new VerifyCS.Test { - LanguageVersion = LanguageVersion.CSharp9, + LanguageVersion = languageVersion, TestCode = initialMarkup, FixedCode = expectedMarkup, CodeActionValidationMode = skipCodeActionValidation @@ -72,6 +76,15 @@ private static Task VerifyMissingAsync(string initialMarkup) [InlineData("a?.b?.c.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] [InlineData("a?.b?.c?.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] + [InlineData("a.b.c.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] + [InlineData("a?.b.c.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] + [InlineData("a.b?.c.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] + [InlineData("a.b.c?.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] + [InlineData("a.b?.c?.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] + [InlineData("a?.b.c?.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] + [InlineData("a?.b?.c.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] + [InlineData("a?.b?.c?.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] + [InlineData("a.b.m().d && a.b.m().a", "a.b.m() is { d: n, a: n }")] [InlineData("a.m().c.d && a.m().a", "a.m() is { c: { d: n }, a: n }")] [InlineData("a?.m().c.d && a?.m().a", "a?.m() is { c: { d: n }, a: n }")] @@ -81,9 +94,9 @@ private static Task VerifyMissingAsync(string initialMarkup) [InlineData("a?.m().c?.d && a?.m().a", "a?.m() is { c: { d: n }, a: n }")] [InlineData("a?.m()?.c.d && a?.m().a", "a?.m() is { c: { d: n }, a: n }")] [InlineData("a?.m()?.c?.d && a?.m().a", "a?.m() is { c: { d: n }, a: n }")] - public async Task TestLogicalAndExpression_Receiver(string actual, string expected) + public async Task TestLogicalAndExpression_Receiver(string actual, string expected, LanguageVersion languageVersion = LanguageVersion.CSharp9) { - await VerifyAsync(WrapInIfStatement("n == " + actual + " == n", "&&"), WrapInIfStatement(expected)); + await VerifyAsync(WrapInIfStatement("n == " + actual + " == n", "&&"), WrapInIfStatement(expected), languageVersion: languageVersion); } [Theory] diff --git a/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/AbstractCSharpArgumentProviderTests`1.cs b/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/AbstractCSharpArgumentProviderTests`1.cs index b0409b04245fd..963c0f457e37e 100644 --- a/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/AbstractCSharpArgumentProviderTests`1.cs +++ b/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/AbstractCSharpArgumentProviderTests`1.cs @@ -2,8 +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 System.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities.Completion; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.ArgumentProviders { @@ -11,5 +16,10 @@ public abstract class AbstractCSharpArgumentProviderTests : AbstractArgumentProviderTests where TWorkspaceFixture : TestWorkspaceFixture, new() { + protected override (SyntaxNode argumentList, ImmutableArray arguments) GetArgumentList(SyntaxToken token) + { + var argumentList = token.GetRequiredParent().GetAncestorsOrThis().First(); + return (argumentList, argumentList.Arguments.ToImmutableArray()); + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/ArgumentProviderOrderTests.cs b/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/ArgumentProviderOrderTests.cs index d9a74abb17ea6..c1002dd079233 100644 --- a/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/ArgumentProviderOrderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/ArgumentProviderOrderTests.cs @@ -36,6 +36,7 @@ public void TestArgumentProviderOrder() // Built-in providers typeof(ContextVariableArgumentProvider), + typeof(OutVariableArgumentProvider), typeof(DefaultArgumentProvider), // Marker for end of built-in argument providers diff --git a/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/ContextVariableArgumentProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/ContextVariableArgumentProviderTests.cs index d4903b595afa5..acb913736e4e8 100644 --- a/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/ContextVariableArgumentProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/ContextVariableArgumentProviderTests.cs @@ -41,6 +41,37 @@ void Target({type} arg) await VerifyDefaultValueAsync(markup, expectedDefaultValue: null, previousDefaultValue: "prior"); } + [Theory] + [CombinatorialData] + public async Task TestOutVariable( + [CombinatorialValues("string", "bool", "int?")] string type, + [CombinatorialValues("out", "ref", "in")] string modifier) + { + var markup = $@" +class C +{{ + void Method() + {{ + {type} arg; + this.Target($$); + }} + + void Target({modifier} {type} arg) + {{ + }} +}} +"; + + var generatedModifier = modifier switch + { + "in" => "", + _ => $"{modifier} ", + }; + + await VerifyDefaultValueAsync(markup, $"{generatedModifier}arg"); + await VerifyDefaultValueAsync(markup, expectedDefaultValue: null, previousDefaultValue: "prior"); + } + [Theory] [InlineData("string")] [InlineData("bool")] @@ -66,22 +97,25 @@ void Target({type} arg) } [Theory] - [InlineData("string")] - [InlineData("bool")] - [InlineData("int?")] - public async Task TestInstanceVariable(string type) + [InlineData("string", "string")] + [InlineData("string", "IEnumerable")] + [InlineData("bool", "bool")] + [InlineData("int?", "int?")] + [InlineData("int", "int?")] + public async Task TestInstanceVariable(string fieldType, string parameterType) { var markup = $@" +using System.Collections.Generic; class C {{ - {type} arg; + {fieldType} arg; void Method() {{ this.Target($$); }} - void Target({type} arg) + void Target({parameterType} arg) {{ }} }} @@ -91,8 +125,86 @@ void Target({type} arg) await VerifyDefaultValueAsync(markup, expectedDefaultValue: null, previousDefaultValue: "prior"); } - // Note: The current implementation checks for exact type and name match. If this changes, some of these tests - // may need to be updated to account for the new behavior. + [Theory] + [InlineData("C")] + [InlineData("B")] + [InlineData("I")] + public async Task TestThisInstance(string parameterType) + { + var markup = $@" +using System.Collections.Generic; +interface I {{ }} + +class B {{ }} + +class C : B, I +{{ + void Method() + {{ + this.Target($$); + }} + + void Target({parameterType} arg) + {{ + }} +}} +"; + + await VerifyDefaultValueAsync(markup, "this"); + await VerifyDefaultValueAsync(markup, expectedDefaultValue: null, previousDefaultValue: "prior"); + } + + [Theory] + [InlineData("object")] + [InlineData("string")] + public async Task TestThisInstanceNotProvided1(string parameterType) + { + var markup = $@" +using System.Collections.Generic; +interface I {{ }} + +class B {{ }} + +class C : B, I +{{ + void Method() + {{ + this.Target($$); + }} + + void Target({parameterType} arg) + {{ + }} +}} +"; + + await VerifyDefaultValueAsync(markup, null); + } + + [Fact] + public async Task TestThisInstanceNotProvided2() + { + var markup = $@" +using System.Collections.Generic; + +class C +{{ + static void Method() + {{ + Target($$); + }} + + static void Target(C arg) + {{ + }} +}} +"; + + await VerifyDefaultValueAsync(markup, null); + } + + // Note: The current implementation checks for exact type match for primitive types. If this changes, some of + // these tests may need to be updated to account for the new behavior. [Theory] [InlineData("object", "string")] [InlineData("string", "object")] diff --git a/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/OutVariableArgumentProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/OutVariableArgumentProviderTests.cs new file mode 100644 index 0000000000000..73f8255bd6251 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Completion/ArgumentProviders/OutVariableArgumentProviderTests.cs @@ -0,0 +1,139 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Completion.Providers; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.ArgumentProviders +{ + [Trait(Traits.Feature, Traits.Features.Completion)] + public class OutVariableArgumentProviderTests : AbstractCSharpArgumentProviderTests + { + private static readonly OptionsCollection s_useExplicitTypeOptions = new(LanguageNames.CSharp) + { + { CSharpCodeStyleOptions.VarForBuiltInTypes, false }, + { CSharpCodeStyleOptions.VarWhenTypeIsApparent, false }, + { CSharpCodeStyleOptions.VarElsewhere, false }, + }; + + private static readonly OptionsCollection s_useExplicitMetadataTypeOptions = new(LanguageNames.CSharp) + { + { CSharpCodeStyleOptions.VarForBuiltInTypes, false }, + { CSharpCodeStyleOptions.VarWhenTypeIsApparent, false }, + { CSharpCodeStyleOptions.VarElsewhere, false }, + { CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, false }, + }; + + private static readonly OptionsCollection s_useImplicitTypeOptions = new(LanguageNames.CSharp) + { + { CSharpCodeStyleOptions.VarForBuiltInTypes, true }, + { CSharpCodeStyleOptions.VarWhenTypeIsApparent, true }, + { CSharpCodeStyleOptions.VarElsewhere, true }, + }; + + internal override Type GetArgumentProviderType() + => typeof(OutVariableArgumentProvider); + + [Theory] + [InlineData("")] + [InlineData("ref")] + [InlineData("in")] + public async Task TestUnsupportedModifiers(string modifier) + { + var markup = $@" +class C +{{ + void Method() + {{ + TryParse($$) + }} + + bool TryParse({modifier} int value) => throw null; +}} +"; + + await VerifyDefaultValueAsync(markup, expectedDefaultValue: null); + } + + [Fact] + public async Task TestDeclareVariable() + { + var markup = $@" +class C +{{ + void Method() + {{ + int.TryParse(""x"", $$) + }} +}} +"; + + await VerifyDefaultValueAsync(markup, "out var result"); + await VerifyDefaultValueAsync(markup, expectedDefaultValue: null, previousDefaultValue: "prior"); + } + + [Theory(Skip = "https://github.com/dotnet/roslyn/issues/53056")] + [CombinatorialData] + public async Task TestDeclareVariableBuiltInType(bool preferVar, bool preferBuiltInType) + { + var markup = $@" +using System; +class C +{{ + void Method() + {{ + int.TryParse(""x"", $$) + }} +}} +"; + + var expected = (preferVar, preferBuiltInType) switch + { + (true, _) => "out var result", + (false, true) => "out int result", + (false, false) => "out Int32 result", + }; + + var options = (preferVar, preferBuiltInType) switch + { + (true, _) => s_useImplicitTypeOptions, + (false, true) => s_useExplicitTypeOptions, + (false, false) => s_useExplicitMetadataTypeOptions, + }; + + await VerifyDefaultValueAsync(markup, expected, options: options); + } + + [Theory] + [InlineData("string")] + [InlineData("bool")] + [InlineData("int?")] + public async Task TestDeclareVariableEscapedIdentifier(string type) + { + var markup = $@" +class C +{{ + void Method() + {{ + this.Target($$); + }} + + void Target(out {type} @void) + {{ + @void = default; + }} +}} +"; + + await VerifyDefaultValueAsync(markup, "out var @void"); + await VerifyDefaultValueAsync(markup, expectedDefaultValue: null, previousDefaultValue: "prior"); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs index 34afa21d5cfae..b4d8e61d2437f 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs @@ -691,6 +691,126 @@ void InnerGoo(DbContext $$) { } } } + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(36248, "https://github.com/dotnet/roslyn/issues/36248")] + public async Task Parameter13() + { + using var workspaceFixture = GetOrCreateWorkspaceFixture(); + + var workspace = workspaceFixture.Target.GetWorkspace(ExportProvider); + workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options.WithChangedOption( + new OptionKey2(NamingStyleOptions.NamingPreferences, LanguageNames.CSharp), + ParameterCamelCaseWithPascalCaseFallback()))); + + var markup = @" +using System.Threading; +public class C +{ + void Goo(CancellationToken $$ +} +"; + await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter); + await VerifyItemIsAbsentAsync(markup, "CancellationToken"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(52534, "https://github.com/dotnet/roslyn/issues/52534")] + public async Task SuggestParameterNamesFromExistingOverloads() + { + var markup = @" +using System.Threading; +public class C +{ + void M(CancellationToken myTok) { } + + void M(CancellationToken $$ +} +"; + await VerifyItemExistsAsync(markup, "myTok", glyph: (int)Glyph.Parameter); + await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(52534, "https://github.com/dotnet/roslyn/issues/52534")] + public async Task SuggestParameterNamesFromExistingOverloads_Constructor() + { + var markup = @" +using System.Threading; +public class C +{ + public C(string firstName, string middleName, string lastName) { } + + public C(string firstName, string $$) +} +"; + await VerifyItemExistsAsync(markup, "middleName", glyph: (int)Glyph.Parameter); + await VerifyItemExistsAsync(markup, "lastName", glyph: (int)Glyph.Parameter); + await VerifyItemIsAbsentAsync(markup, "firstName"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(52534, "https://github.com/dotnet/roslyn/issues/52534")] + public async Task DoNotSuggestParameterNamesFromTheSameOverload() + { + var markup = @" +public class C +{ + void M(string name, string $$) { } +} +"; + await VerifyItemIsAbsentAsync(markup, "name"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(52534, "https://github.com/dotnet/roslyn/issues/52534")] + public async Task DoNotSuggestParameterNamesFromNonOverloads() + { + var markup = @" +using System.Threading; +public class C +{ + void M1(CancellationToken myTok) { } + + void M2(CancellationToken $$ +} +"; + await VerifyItemIsAbsentAsync(markup, "myTok"); + await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(52534, "https://github.com/dotnet/roslyn/issues/52534")] + public async Task DoNotSuggestInGenericType() + { + var markup = @" +using System.Collections.Generic; +public class C +{ + void M(IEnumerable numbers) { } + + void M(List<$$>) { } +} +"; + await VerifyNoItemsExistAsync(markup); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(52534, "https://github.com/dotnet/roslyn/issues/52534")] + public async Task DoNotSuggestInOptionalParameterDefaultValue() + { + var markup = @" +using System.Collections.Generic; +public class C +{ + private const int ZERO = 0; + void M(int num = ZERO) { } + + void M(int x, int num = $$) { } +} +"; + await VerifyNoItemsExistAsync(markup); + } + [WorkItem(19260, "https://github.com/dotnet/roslyn/issues/19260")] [Fact, Trait(Traits.Feature, Traits.Features.Completion)] public async Task EscapeKeywords1() @@ -2702,6 +2822,44 @@ private static NamingStylePreferences NamesEndWithSuffixPreferences() } } + private static NamingStylePreferences ParameterCamelCaseWithPascalCaseFallback() + { + var symbolSpecifications = ImmutableArray.Create( + new SymbolSpecification( + id: Guid.NewGuid(), + symbolSpecName: "parameters", + ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Parameter)), + accessibilityList: default, + modifiers: default), + new SymbolSpecification( + id: Guid.NewGuid(), + symbolSpecName: "fallback", + ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Parameter), new SymbolKindOrTypeKind(SymbolKind.Local)), + accessibilityList: default, + modifiers: default)); + var namingStyles = ImmutableArray.Create( + new NamingStyle( + Guid.NewGuid(), + name: "parameter", + capitalizationScheme: Capitalization.CamelCase, + prefix: "", + suffix: "", + wordSeparator: ""), + new NamingStyle( + Guid.NewGuid(), + name: "any_symbol", + capitalizationScheme: Capitalization.PascalCase, + prefix: "", + suffix: "", + wordSeparator: "")); + return new NamingStylePreferences( + symbolSpecifications, + namingStyles, + namingRules: ImmutableArray.Create( + CreateRule(symbolSpecifications[0], namingStyles[0]), + CreateRule(symbolSpecifications[1], namingStyles[1]))); + } + private static SerializableNamingRule CreateRule(SymbolSpecification specification, NamingStyle style) { return new SerializableNamingRule() diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs index 82d590bc2f1cd..0748171414e87 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProviderTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; @@ -577,5 +575,318 @@ void IGoo.this[ await VerifyProviderCommitAsync(markup, "this[K key, V value]", expected, '['); } + + [Theory, Trait(Traits.Feature, Traits.Features.Completion)] + [InlineData("ref")] + [InlineData("in")] + [InlineData("out")] + public async Task TestWithRefKind(string refKind) + { + var markup = $@" +interface I +{{ + void M({refKind} string s); +}} + +class C : I +{{ + void I.$$ +}} +"; + + var expected = $@" +interface I +{{ + void M({refKind} string s); +}} + +class C : I +{{ + void I.M({refKind} string s) +}} +"; + + await VerifyProviderCommitAsync(markup, $"M({refKind} string s)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(53924, "https://github.com/dotnet/roslyn/issues/53924")] + public async Task TestStaticAbstractInterfaceMember() + { + var markup = @" +interface I2 where T : I2 +{ + abstract static implicit operator int(T x); +} + +class Test2 : I2 +{ + static implicit I2.$$ +} +"; + + var expected = @" +interface I2 where T : I2 +{ + abstract static implicit operator int(T x); +} + +class Test2 : I2 +{ + static implicit I2.operator int(Test2 x) +} +"; + + await VerifyProviderCommitAsync(markup, "operator int(Test2 x)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(53924, "https://github.com/dotnet/roslyn/issues/53924")] + public async Task TestStaticAbstractInterfaceMember_TrueOperator() + { + var markup = @" +interface I where T : I +{ + abstract static bool operator true(T x); + abstract static bool operator false(T x); +} + +class C : I +{ + static bool I.$$ +} +"; + + var expected = @" +interface I where T : I +{ + abstract static bool operator true(T x); + abstract static bool operator false(T x); +} + +class C : I +{ + static bool I.operator true(C x) +} +"; + + await VerifyProviderCommitAsync(markup, "operator true(C x)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(53924, "https://github.com/dotnet/roslyn/issues/53924")] + public async Task TestStaticAbstractInterfaceMember_UnaryPlusOperator() + { + var markup = @" +interface I where T : I +{ + abstract static T operator +(T x); +} + +class C : I +{ + static C I.$$ +} +"; + + var expected = @" +interface I where T : I +{ + abstract static T operator +(T x); +} + +class C : I +{ + static C I.operator +(C x) +} +"; + + await VerifyProviderCommitAsync(markup, "operator +(C x)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(53924, "https://github.com/dotnet/roslyn/issues/53924")] + public async Task TestStaticAbstractInterfaceMember_BinaryPlusOperator() + { + var markup = @" +interface I where T : I +{ + abstract static T operator +(T x, T y); +} + +class C : I +{ + static C I.$$ +} +"; + + var expected = @" +interface I where T : I +{ + abstract static T operator +(T x, T y); +} + +class C : I +{ + static C I.operator +(C x, C y) +} +"; + + await VerifyProviderCommitAsync(markup, "operator +(C x, C y)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task TestWithParamsParameter() + { + var markup = @" +interface I +{ + void M(params string[] args); +} + +class C : I +{ + void I.$$ +} +"; + + var expected = @" +interface I +{ + void M(params string[] args); +} + +class C : I +{ + void I.M(params string[] args) +} +"; + + await VerifyProviderCommitAsync(markup, "M(params string[] args)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task TestWithNullable() + { + var markup = @" +#nullable enable + +interface I +{ + void M(T? x); +} + +class C : I +{ + void I.$$ +} +"; + + var expected = @" +#nullable enable + +interface I +{ + void M(T? x); +} + +class C : I +{ + void I.M(T? x) +} +"; + + await VerifyProviderCommitAsync(markup, "M(T? x)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task TestEscapeIdentifier() + { + var markup = @" +interface I +{ + void M(string @class); +} + +class C : I +{ + void I.$$ +} +"; + + var expected = @" +interface I +{ + void M(string @class); +} + +class C : I +{ + void I.M(string @class) +} +"; + + await VerifyProviderCommitAsync(markup, "M(string @class)", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task TestEscapeIdentifier2() + { + var markup = @" +interface I +{ + void M<@class>(); +} + +class C : I +{ + void I.$$ +} +"; + + var expected = @" +interface I +{ + void M<@class>(); +} + +class C : I +{ + void I.M<@class>() +} +"; + + await VerifyProviderCommitAsync(markup, "M<@class>()", expected, '\t'); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task TestParameterWithDefaultValue() + { + var markup = @" +interface I +{ + void M(int x = 10); +} + +class C : I +{ + void I.$$ +} +"; + + var expected = @" +interface I +{ + void M(int x = 10); +} + +class C : I +{ + void I.M(int x) +} +"; + // TODO: Consider adding the default value too. + await VerifyProviderCommitAsync(markup, "M(int x)", expected, '\t'); + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs index 4adad3be4517d..9886e5e30e0f6 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs @@ -8,11 +8,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; using Roslyn.Test.Utilities; @@ -27,8 +25,7 @@ public class ExtensionMethodImportCompletionProviderTests : AbstractCSharpComple public ExtensionMethodImportCompletionProviderTests() { ShowImportCompletionItemsOptionValue = true; - TimeoutInMilliseconds = -1; // -1 disables timeout - IsExpandedCompletion = true; + ForceExpandedCompletionIndexCreation = true; } internal override Type GetCompletionProviderType() @@ -1933,44 +1930,6 @@ public void M() await VerifyProviderCommitAsync(markup, "ToInt", expected, commitChar: commitChar, sourceCodeKind: SourceCodeKind.Regular); } - [Fact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task TestTimeBox() - { - var file1 = @" -using System; - -namespace Foo -{ - public static class ExtensionClass - { - public static bool ExtentionMethod(this int x) - => true; - } -}"; - var file2 = @" -using System; - -namespace Baz -{ - public class Bat - { - public void M(int x) - { - x.$$ - } - } -}"; - - IsExpandedCompletion = false; - TimeoutInMilliseconds = 0; //timeout immediately - var markup = GetMarkup(file2, file1, ReferenceType.None); - - await VerifyImportItemIsAbsentAsync( - markup, - "ExtentionMethod", - inlineDescription: "Foo"); - } - [InlineData("int", true, "int a")] [InlineData("int[]", true, "int a, int b")] [InlineData("bool", false, null)] diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs index ebbf3fa1e7207..a5460b6c00618 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Completion.Providers; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; @@ -79,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)); + Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(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 4dde8138a4d5e..11326f4e2f938 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs @@ -1206,7 +1206,7 @@ private async Task VerifyExclusiveAsync(string markup, bool exclusive) var service = GetCompletionService(document.Project); var completionList = await GetCompletionListAsync(service, document, position, triggerInfo); - if (completionList != null) + if (!completionList.IsEmpty) { Assert.True(exclusive == completionList.GetTestAccessor().IsExclusive, "group.IsExclusive == " + completionList.GetTestAccessor().IsExclusive); } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PropertySubPatternCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PropertySubPatternCompletionProviderTests.cs index 28558765bcfaa..c9edf82f9105c 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PropertySubPatternCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PropertySubPatternCompletionProviderTests.cs @@ -36,8 +36,8 @@ void M() } "; // VerifyItemExistsAsync also tests with the item typed. - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ""); } [Fact] @@ -57,8 +57,8 @@ void M() public void Deconstruct(out int x, out int y) => throw null; } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ""); } [Fact] @@ -78,8 +78,8 @@ void M() public void Deconstruct(out int x, out int y) => throw null; } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ""); } [Fact] @@ -98,8 +98,8 @@ void M() } } "; - await VerifyItemExistsAsync(markup, "@new", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "@struct", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "@new", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "@struct", displayTextSuffix: ""); } [Fact] @@ -138,8 +138,8 @@ class Derived public int P2 { get; set; } } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ""); } [Fact] @@ -160,8 +160,8 @@ class Other public int F2; } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "F2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "F2", displayTextSuffix: ""); } [Fact] @@ -203,7 +203,7 @@ class Derived : Program private int P2 { get; set; } } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); } [Fact] @@ -223,8 +223,8 @@ void M() } "; // VerifyItemExistsAsync also tests with the item typed. - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ""); } [Fact] @@ -247,8 +247,8 @@ void M() } "; // VerifyItemExistsAsync also tests with the item typed. - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ""); } [Fact] @@ -271,8 +271,8 @@ void M() } "; // VerifyItemExistsAsync also tests with the item typed. - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ""); } [Fact] @@ -291,8 +291,8 @@ void M() } } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ""); } [Fact] @@ -318,8 +318,8 @@ void M() "; await VerifyItemIsAbsentAsync(markup, "P1"); await VerifyItemIsAbsentAsync(markup, "P2"); - await VerifyItemExistsAsync(markup, "P3", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P4", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P3", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P4", displayTextSuffix: ""); } [Fact] @@ -345,8 +345,8 @@ void M() "; await VerifyItemIsAbsentAsync(markup, "P1"); await VerifyItemIsAbsentAsync(markup, "F2"); - await VerifyItemExistsAsync(markup, "P3", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P4", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P3", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P4", displayTextSuffix: ""); } [Fact] @@ -372,8 +372,8 @@ void M() "; await VerifyItemIsAbsentAsync(markup, "P1"); await VerifyItemIsAbsentAsync(markup, "P2"); - await VerifyItemExistsAsync(markup, "F3", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "F4", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "F3", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "F4", displayTextSuffix: ""); } [Fact] @@ -455,7 +455,7 @@ void M() } "; // VerifyItemExistsAsync also tests with the item typed. - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); await VerifyItemIsAbsentAsync(markup, "P2"); } @@ -542,7 +542,7 @@ void M() public void Deconstruct(out Program x, out Program y) => throw null; } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); } [Fact] @@ -562,7 +562,7 @@ void M() public void Deconstruct(out Program x, out Program y) => throw null; } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); } [Fact] @@ -604,7 +604,7 @@ void M() public void Deconstruct(out Program x, out Program y) => throw null; } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); } [Fact] @@ -624,7 +624,7 @@ void M() public void Deconstruct(out Program x, out Program y) => throw null; } "; - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); } [Fact] @@ -665,8 +665,8 @@ void M() } "; // Ignore browsability limiting attributes if the symbol is declared in source. - await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ":"); - await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ":"); + await VerifyItemExistsAsync(markup, "P1", displayTextSuffix: ""); + await VerifyItemExistsAsync(markup, "P2", displayTextSuffix: ""); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs index 3431ea644504d..495eac7f70905 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)); + Assert.Equal(expectedResult, provider.ShouldTriggerCompletion(languageServices, SourceText.From(text), position, trigger: default, CompletionOptions.Default, OptionValueSet.Empty)); } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs index b01ce9c32bc6b..9a090c612ffc6 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs @@ -11532,5 +11532,256 @@ void M(T x) where T : I1, I2 await VerifyItemExistsAsync(source, "P1"); await VerifyItemExistsAsync(source, "E1"); } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58081, "https://github.com/dotnet/roslyn/issues/58081")] + public async Task CompletionOnPointerParameter() + { + var source = @" +struct TestStruct +{ + public int X; + public int Y { get; } + public void Method() { } +} + +unsafe class Test +{ + void TestMethod(TestStruct* a) + { + a->$$ + } +} +"; + await VerifyItemExistsAsync(source, "X"); + await VerifyItemExistsAsync(source, "Y"); + await VerifyItemExistsAsync(source, "Method"); + await VerifyItemExistsAsync(source, "ToString"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58081, "https://github.com/dotnet/roslyn/issues/58081")] + public async Task CompletionOnAwaitedPointerParameter() + { + var source = @" +struct TestStruct +{ + public int X; + public int Y { get; } + public void Method() { } +} + +unsafe class Test +{ + async void TestMethod(TestStruct* a) + { + await a->$$ + } +} +"; + await VerifyItemExistsAsync(source, "X"); + await VerifyItemExistsAsync(source, "Y"); + await VerifyItemExistsAsync(source, "Method"); + await VerifyItemExistsAsync(source, "ToString"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58081, "https://github.com/dotnet/roslyn/issues/58081")] + public async Task CompletionOnLambdaPointerParameter() + { + var source = @" +struct TestStruct +{ + public int X; + public int Y { get; } + public void Method() { } +} + +unsafe class Test +{ + delegate void TestLambda(TestStruct* a); + + TestLambda TestMethod() + { + return a => a->$$ + } +} +"; + await VerifyItemExistsAsync(source, "X"); + await VerifyItemExistsAsync(source, "Y"); + await VerifyItemExistsAsync(source, "Method"); + await VerifyItemExistsAsync(source, "ToString"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58081, "https://github.com/dotnet/roslyn/issues/58081")] + public async Task CompletionOnOverloadedLambdaPointerParameter() + { + + var source = @" +struct TestStruct1 +{ + public int X; +} + +struct TestStruct2 +{ + public int Y; +} + +unsafe class Test +{ + delegate void TestLambda1(TestStruct1* a); + delegate void TestLambda2(TestStruct2* a); + + void Overloaded(TestLambda1 lambda) + { + } + + void Overloaded(TestLambda2 lambda) + { + } + + void TestMethod() + => Overloaded(a => a->$$); +} +"; + await VerifyItemExistsAsync(source, "X"); + await VerifyItemExistsAsync(source, "Y"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58081, "https://github.com/dotnet/roslyn/issues/58081")] + public async Task CompletionOnOverloadedLambdaPointerParameterWithExplicitType() + { + + var source = @" +struct TestStruct1 +{ + public int X; +} + +struct TestStruct2 +{ + public int Y; +} + +unsafe class Test +{ + delegate void TestLambda1(TestStruct1* a); + delegate void TestLambda2(TestStruct2* a); + + void Overloaded(TestLambda1 lambda) + { + } + + void Overloaded(TestLambda2 lambda) + { + } + + void TestMethod() + => Overloaded((TestStruct1* a) => a->$$); +} +"; + await VerifyItemExistsAsync(source, "X"); + await VerifyItemIsAbsentAsync(source, "Y"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58081, "https://github.com/dotnet/roslyn/issues/58081")] + public async Task CompletionOnPointerParameterWithSimpleMemberAccess() + { + var source = @" +struct TestStruct +{ + public int X; + public int Y { get; } + public void Method() { } +} + +unsafe class Test +{ + void TestMethod(TestStruct* a) + { + a.$$ + } +} +"; + await VerifyItemIsAbsentAsync(source, "X"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58081, "https://github.com/dotnet/roslyn/issues/58081")] + public async Task CompletionOnOverloadedLambdaPointerParameterWithSimpleMemberAccess() + { + + var source = @" +struct TestStruct1 +{ + public int X; +} + +struct TestStruct2 +{ + public int Y; +} + +unsafe class Test +{ + delegate void TestLambda1(TestStruct1* a); + delegate void TestLambda2(TestStruct2* a); + + void Overloaded(TestLambda1 lambda) + { + } + + void Overloaded(TestLambda2 lambda) + { + } + + void TestMethod() + => Overloaded(a => a.$$); +} +"; + await VerifyItemIsAbsentAsync(source, "X"); + await VerifyItemIsAbsentAsync(source, "Y"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58081, "https://github.com/dotnet/roslyn/issues/58081")] + public async Task CompletionOnOverloadedLambdaPointerParameterWithSimpleMemberAccessAndExplicitType() + { + + var source = @" +struct TestStruct1 +{ + public int X; +} + +struct TestStruct2 +{ + public int Y; +} + +unsafe class Test +{ + delegate void TestLambda1(TestStruct1* a); + delegate void TestLambda2(TestStruct2* a); + + void Overloaded(TestLambda1 lambda) + { + } + + void Overloaded(TestLambda2 lambda) + { + } + + void TestMethod() + => Overloaded((TestStruct1* a) => a.$$); +} +"; + await VerifyItemIsAbsentAsync(source, "X"); + await VerifyItemIsAbsentAsync(source, "Y"); + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs index fe8d34b942d1e..880595bc1bb14 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; using Microsoft.VisualStudio.Text; @@ -338,7 +339,7 @@ string Property var service = CompletionService.GetService(document); var options = CompletionOptions.Default; var displayOptions = SymbolDescriptionOptions.Default; - var (completions, _) = await service.GetCompletionsInternalAsync(document, position, options); + var completions = await service.GetCompletionsAsync(document, position, options, OptionValueSet.Empty); var item = completions.Items.First(i => i.DisplayText == "Beep"); var edit = testDocument.GetTextBuffer().CreateEdit(); diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs index c8816f7ab5a1f..2dbe4c4df911a 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs @@ -7,11 +7,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -27,7 +25,7 @@ internal override Type GetCompletionProviderType() public TypeImportCompletionProviderTests() { ShowImportCompletionItemsOptionValue = true; - IsExpandedCompletion = true; + ForceExpandedCompletionIndexCreation = true; } #region "Option tests" @@ -52,7 +50,7 @@ class Bar public async Task OptionSetToNull_ExpDisabled() { ShowImportCompletionItemsOptionValue = null; - IsExpandedCompletion = false; + ForceExpandedCompletionIndexCreation = false; var markup = @" class Bar { @@ -69,7 +67,7 @@ public async Task OptionSetToFalse(bool isExperimentEnabled) { TypeImportCompletionFeatureFlag = isExperimentEnabled; ShowImportCompletionItemsOptionValue = false; - IsExpandedCompletion = false; + ForceExpandedCompletionIndexCreation = false; var markup = @" class Bar @@ -1776,6 +1774,67 @@ static MyClass await VerifyProviderCommitAsync(markup, "MyClass", expectedCodeAfterCommit, commitChar: null, sourceCodeKind: kind); } + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58473, "https://github.com/dotnet/roslyn/issues/58473")] + public async Task TestGlobalUsingsInSdkAutoGeneratedFile() + { + var source = @" +using System; +$$"; + + var globalUsings = @" +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; +"; + + var markup = CreateMarkupForSingleProject(source, globalUsings, LanguageNames.CSharp, referencedFileName: "ProjectName.GlobalUsings.g.cs"); + await VerifyTypeImportItemIsAbsentAsync(markup, "Task", inlineDescription: "System.Threading.Tasks"); + await VerifyTypeImportItemIsAbsentAsync(markup, "Console", inlineDescription: "System"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58473, "https://github.com/dotnet/roslyn/issues/58473")] + public async Task TestGlobalUsingsInSameFile() + { + var source = @" +global using global::System; +global using global::System.Threading.Tasks; + +$$"; + + var markup = CreateMarkupForSingleProject(source, "", LanguageNames.CSharp); + await VerifyTypeImportItemIsAbsentAsync(markup, "Console", inlineDescription: "System"); + await VerifyTypeImportItemIsAbsentAsync(markup, "Task", inlineDescription: "System.Threading.Tasks"); + } + + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/59088")] + [Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(58473, "https://github.com/dotnet/roslyn/issues/58473")] + public async Task TestGlobalUsingsInUserDocument() + { + var source = @" +$$"; + + var globalUsings = @" +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; +"; + + var markup = CreateMarkupForSingleProject(source, globalUsings, LanguageNames.CSharp, referencedFileName: "GlobalUsings.cs"); + await VerifyTypeImportItemIsAbsentAsync(markup, "Task", inlineDescription: "System.Threading.Tasks"); + await VerifyTypeImportItemIsAbsentAsync(markup, "Console", inlineDescription: "System"); + } + private Task VerifyTypeImportItemExistsAsync(string markup, string expectedItem, int glyph, string inlineDescription, string displayTextSuffix = null, string expectedDescriptionOrNull = null, CompletionItemFlags? flags = null) => VerifyItemExistsAsync(markup, expectedItem, displayTextSuffix: displayTextSuffix, glyph: glyph, inlineDescription: inlineDescription, expectedDescriptionOrNull: expectedDescriptionOrNull, isComplexTextEdit: true, flags: flags); diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs index 24722df51ca49..e37731a1cc36a 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionServiceTests.cs @@ -4,10 +4,18 @@ #nullable disable +using System; +using System.Collections.Immutable; +using System.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.CSharp.Completion.Providers; +using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -34,6 +42,89 @@ public void AcquireCompletionService() Assert.NotNull(service); } + [ExportCompletionProvider(nameof(ThirdPartyCompletionProvider), LanguageNames.CSharp)] + [ExtensionOrder(After = nameof(KeywordCompletionProvider))] + [Shared] + private sealed class ThirdPartyCompletionProvider : CompletionProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public ThirdPartyCompletionProvider() + { + } + + public override Task ProvideCompletionsAsync(CompletionContext context) + => Task.CompletedTask; + + public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options) + { + Assert.Equal(1, options.GetOption(new OptionKey(ThirdPartyOption.Instance, LanguageNames.CSharp))); + return true; + } + } + + private sealed class ThirdPartyOption : IOption + { + public static ThirdPartyOption Instance = new(); + + public string Feature => "TestOptions"; + public string Name => "Option"; + public Type Type => typeof(int); + public object DefaultValue => 0; + public bool IsPerLanguage => true; + public ImmutableArray StorageLocations => ImmutableArray.Empty; + } + + /// + /// Ensure that 3rd party can set options on solution and access them from within a custom completion provider. + /// + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task PassThroughOptions1() + { + using var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features.AddParts(typeof(ThirdPartyCompletionProvider))); + + var text = SourceText.From("class C { }"); + + var document = workspace.CurrentSolution + .AddProject("TestProject", "Assembly", LanguageNames.CSharp) + .AddDocument("TestDocument.cs", text); + + var service = CompletionService.GetService(document); + var options = new OptionValueSet(ImmutableDictionary.Empty.Add(new OptionKey(ThirdPartyOption.Instance, LanguageNames.CSharp), 1)); + service.ShouldTriggerCompletion(text, 1, CompletionTrigger.Invoke, options: options); + +#pragma warning disable RS0030 // Do not used banned APIs + await service.GetCompletionsAsync(document, 1, CompletionTrigger.Invoke, options: options); +#pragma warning restore + } + + /// + /// Ensure that 3rd party can set options on solution and access them from within a custom completion provider. + /// + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task PassThroughOptions2() + { + using var workspace = new TestWorkspace(composition: EditorTestCompositions.EditorFeatures.AddParts(typeof(ThirdPartyCompletionProvider))); + + var testDocument = new TestHostDocument("class C {}"); + var project = new TestHostProject(workspace, testDocument, name: "project1"); + workspace.AddTestProject(project); + workspace.OpenDocument(testDocument.Id); + + Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions( + workspace.CurrentSolution.Options.WithChangedOption(new OptionKey(ThirdPartyOption.Instance, LanguageNames.CSharp), 1)))); + + var document = workspace.CurrentSolution.GetDocument(testDocument.Id); + var text = await document.GetTextAsync(); + + var service = CompletionService.GetService(document); + service.ShouldTriggerCompletion(text, 1, CompletionTrigger.Invoke, options: null); + +#pragma warning disable RS0030 // Do not used banned APIs + await service.GetCompletionsAsync(document, 1, CompletionTrigger.Invoke, options: null); +#pragma warning restore + } + [Theory, CombinatorialData] public async Task GettingCompletionListShoudNotRunSourceGenerator(bool forkBeforeFreeze) { @@ -61,7 +152,7 @@ public class C1 Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); var document = workspace.CurrentSolution.Projects.Single().Documents.Single(); - var compeltionService = document.GetLanguageService(); + var completionService = document.GetLanguageService(); Assert.Equal(0, generatorRanCount); @@ -73,9 +164,8 @@ public class C1 } // We want to make sure import completion providers are also participating. - var options = CompletionOptions.From(document.Project.Solution.Options, document.Project.Language); - var newOptions = options with { ShowItemsFromUnimportedNamespaces = true }; - var (completionList, _) = await compeltionService.GetCompletionsInternalAsync(document, position.Value, options: newOptions); + var options = CompletionOptions.Default with { ShowItemsFromUnimportedNamespaces = true }; + var completionList = await completionService.GetCompletionsAsync(document, position.Value, options, OptionValueSet.Empty); // We expect completion to run on frozen partial semantic, which won't run source generator. Assert.Equal(0, generatorRanCount); diff --git a/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs b/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs new file mode 100644 index 0000000000000..2b45607483b73 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs @@ -0,0 +1,773 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.ConvertToRawString; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertToRawString +{ + using VerifyCS = CSharpCodeRefactoringVerifier< + ConvertRegularStringToRawStringCodeRefactoringProvider>; + + public class ConvertToRegularStringToRawStringStringTests + { + private static async Task VerifyRefactoringAsync(string testCode, string fixedCode, int index = 0, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary) + { + await new VerifyCS.Test + { + TestCode = testCode, + FixedCode = fixedCode, + LanguageVersion = LanguageVersionExtensions.CSharpNext, + CodeActionIndex = index, + TestState = + { + OutputKind = outputKind, + }, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNotInDirective() + { + var code = @" +#line 1 [||]""goo.cs"""; + + await VerifyRefactoringAsync(code, code); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNotOnEmptyString() + { + var code = @"public class C +{ + void M() + { + var v = [||]""""; + } +}"; + + await VerifyRefactoringAsync(code, code); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNotOnEmptyVerbatimString() + { + var code = @"public class C +{ + void M() + { + var v = [||]@""""; + } +}"; + + await VerifyRefactoringAsync(code, code); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNotOnHighSurrogateChar() + { + var code = @"public class C +{ + void M() + { + var v = [||]""\uD800""; + } +}"; + + await VerifyRefactoringAsync(code, code); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNotOnLowSurrogateChar1() + { + var code = @"public class C +{ + void M() + { + var v = [||]""\uDC00""; + } +}"; + + await VerifyRefactoringAsync(code, code); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestOnCombinedSurrogate() + { + await VerifyRefactoringAsync( +@"public class C +{ + void M() + { + var v = [||]""\uD83D\uDC69""; + } +}", +@"public class C +{ + void M() + { + var v = """"""👩""""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNotOnNullChar() + { + var code = @"public class C +{ + void M() + { + var v = [||]""\u0000""; + } +}"; + + await VerifyRefactoringAsync(code, code); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNotOnControlCharacter() + { + var code = @"public class C +{ + void M() + { + var v = [||]""\u007F""; + } +}"; + + await VerifyRefactoringAsync(code, code); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestSimpleString() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""a""; + } +}", @"public class C +{ + void M() + { + var v = """"""a""""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestVerbatimSimpleString() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""a""; + } +}", @"public class C +{ + void M() + { + var v = """"""a""""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestSimpleStringTopLevel() + { + await VerifyRefactoringAsync(@" +var v = [||]""a""; +", @" +var v = """"""a""""""; +", outputKind: OutputKind.ConsoleApplication); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestStringWithQuoteInMiddle() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""goo\""bar""; + } +}", @"public class C +{ + void M() + { + var v = """"""goo""bar""""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestVerbatimStringWithQuoteInMiddle() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""goo""""bar""; + } +}", @"public class C +{ + void M() + { + var v = """"""goo""bar""""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestStringWithQuoteAtStart() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""\""goobar""; + } +}", @"public class C +{ + void M() + { + var v = """""" + ""goobar + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentStringWithQuoteAtStart() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""\""goobar""; + } +}", @"public class C +{ + void M() + { + var v = """""" +""goobar +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestVerbatimStringWithQuoteAtStart() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""""""goobar""; + } +}", @"public class C +{ + void M() + { + var v = """""" + ""goobar + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentVerbatimStringWithQuoteAtStart() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""""""goobar""; + } +}", @"public class C +{ + void M() + { + var v = """""" +""goobar +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestStringWithQuoteAtEnd() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""goobar\""""; + } +}", @"public class C +{ + void M() + { + var v = """""" + goobar"" + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentStringWithQuoteAtEnd() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""goobar\""""; + } +}", @"public class C +{ + void M() + { + var v = """""" +goobar"" +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestVerbatimStringWithQuoteAtEnd() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""goobar""""""; + } +}", @"public class C +{ + void M() + { + var v = """""" + goobar"" + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentVerbatimStringWithQuoteAtEnd() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""goobar""""""; + } +}", @"public class C +{ + void M() + { + var v = """""" +goobar"" +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestStringWithNewLine() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""goo\r\nbar""; + } +}", @"public class C +{ + void M() + { + var v = """""" + goo + bar + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentStringWithNewLine() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""goo\r\nbar""; + } +}", @"public class C +{ + void M() + { + var v = """""" +goo +bar +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestVerbatimStringWithNewLine() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""goo +bar""; + } +}", @"public class C +{ + void M() + { + var v = """""" + goo + bar + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentVerbatimStringWithNewLine() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""goo +bar""; + } +}", @"public class C +{ + void M() + { + var v = """""" +goo +bar +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestStringWithNewLineAtStartAndEnd() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""\r\ngoobar\r\n""; + } +}", @"public class C +{ + void M() + { + var v = """""" + + goobar + + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentStringWithNewLineAtStartAndEnd() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""\r\ngoobar\r\n""; + } +}", @"public class C +{ + void M() + { + var v = """""" + +goobar + +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestVerbatimStringWithNewLineAtStartAndEnd() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@"" +goobar +""; + } +}", @"public class C +{ + void M() + { + var v = """""" + + goobar + + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentVerbatimStringWithNewLineAtStartAndEnd() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@"" +goobar +""; + } +}", @"public class C +{ + void M() + { + var v = """""" + +goobar + +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestIndentedString() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""goo\r\nbar""; + } +}", @"public class C +{ + void M() + { + var v = """""" + goo + bar + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentedString() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]""goo\r\nbar""; + } +}", @"public class C +{ + void M() + { + var v = """""" +goo +bar +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestIndentedStringTopLevel() + { + await VerifyRefactoringAsync(@" +var v = [||]""goo\r\nbar""; +", @" +var v = """""" + goo + bar + """"""; +", outputKind: OutputKind.ConsoleApplication); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentedStringTopLevel() + { + await VerifyRefactoringAsync(@" +var v = [||]""goo\r\nbar""; +", @" +var v = """""" +goo +bar +""""""; +", index: 1, outputKind: OutputKind.ConsoleApplication); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestVerbatimIndentedString() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""goo +bar""; + } +}", @"public class C +{ + void M() + { + var v = """""" + goo + bar + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentVerbatimIndentedString() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@""goo +bar""; + } +}", @"public class C +{ + void M() + { + var v = """""" +goo +bar +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestIndentedStringOnOwnLine() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = + [||]""goo\r\nbar""; + } +}", @"public class C +{ + void M() + { + var v = + """""" + goo + bar + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentedStringOnOwnLine() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = + [||]""goo\r\nbar""; + } +}", @"public class C +{ + void M() + { + var v = + """""" +goo +bar +""""""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestVerbatimIndentedStringOnOwnLine() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = + [||]@""goo +bar""; + } +}", @"public class C +{ + void M() + { + var v = + """""" + goo + bar + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestNoIndentVerbatimIndentedStringOnOwnLine() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = + [||]@""goo +bar""; + } +}", @"public class C +{ + void M() + { + var v = + """""" +goo +bar +""""""; + } +}", index: 1); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.cs b/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.cs index 6865676c9edb9..bf87813998e92 100644 --- a/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.cs +++ b/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.cs @@ -22,6 +22,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Debugging { [UseExportProvider] + [Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] public partial class ProximityExpressionsGetterTests { private static string s_lazyTestFileContent; @@ -44,7 +45,7 @@ private static SyntaxTree GetTree() private static SyntaxTree GetTreeFromCode(string code) => SyntaxFactory.ParseSyntaxTree(code); - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public void TestWithinStatement_1() { var tree = GetTreeFromCode(@"using System; @@ -83,17 +84,34 @@ private static async Task TestProximityExpressionGetterAsync( await continuation(proximityExpressionsGetter, document, caretPosition); } + private static async Task TestTryDoInMainAsync(string body, bool topLevelStatement, params string[] expectedTerms) + { + string input; + if (topLevelStatement) + { + input = body; + } + else + { + input = $@"class Program +{{ + static void Main(string[] args) + {{ +{string.Join(Environment.NewLine, body.ReplaceLineEndings("\n").Split('\n').Select(line => line == "" ? line : $" {line}"))} + }} +}}"; + } + + await TestTryDoAsync(input, expectedTerms); + } + private static async Task TestTryDoAsync(string input, params string[] expectedTerms) { await TestProximityExpressionGetterAsync(input, async (getter, document, position) => { var actualTerms = await getter.GetProximityExpressionsAsync(document, position, CancellationToken.None); - - Assert.Equal(expectedTerms.Length == 0, actualTerms == null); - if (expectedTerms.Length > 0) - { - AssertEx.Equal(expectedTerms, actualTerms); - } + Assert.True(actualTerms is null or { Count: > 0 }); + AssertEx.Equal(expectedTerms, actualTerms ?? Array.Empty()); }); } @@ -106,42 +124,42 @@ await TestProximityExpressionGetterAsync(input, async (getter, semanticSnapshot, }); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestTryDo1() => await TestTryDoAsync("class Class { void Method() { string local;$$ } }", "local", "this"); - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestNoParentToken() => await TestTryDoAsync("$$"); - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestIsValid1() => await TestIsValidAsync("class Class { void Method() { string local;$$ } }", "local", true); - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestIsValidWithDiagnostics() { // local doesn't exist in this context await TestIsValidAsync("class Class { void Method() { string local; } $$}", "local", false); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestIsValidReferencingLocalBeforeDeclaration() => await TestIsValidAsync("class Class { void Method() { $$int i; int j; } }", "j", false); - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestIsValidReferencingUndefinedVariable() => await TestIsValidAsync("class Class { void Method() { $$int i; int j; } }", "k", false); - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestIsValidNoTypeSymbol() => await TestIsValidAsync("namespace Namespace$$ { }", "goo", false); - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestIsValidLocalAfterPosition() => await TestIsValidAsync("class Class { void Method() { $$ int i; string local; } }", "local", false); - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestThis() { await TestTryDoAsync(@" @@ -155,10 +173,12 @@ public Class() : this(true) }", "this"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestArrayCreationExpression() + [Theory, CombinatorialData] + public async Task TestArrayCreationExpression(bool topLevelStatement) { - await TestTryDoAsync(@" + if (!topLevelStatement) + { + await TestTryDoAsync(@" class Class { void Method() @@ -166,12 +186,19 @@ void Method() int[] i = new int[] { 3 }$$; } }", "i", "this"); + } + + await TestTryDoInMainAsync(@" +int[] i = new int[] { 3 }$$; +", topLevelStatement, "i", "args"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestPostfixUnaryExpressionSyntax() + [Theory, CombinatorialData] + public async Task TestPostfixUnaryExpressionSyntax(bool topLevelStatement) { - await TestTryDoAsync(@" + if (!topLevelStatement) + { + await TestTryDoAsync(@" class Class { void Method() @@ -180,12 +207,19 @@ void Method() i++$$; } }", "i", "this"); + } + + await TestTryDoInMainAsync(@"int i = 3; +i++$$; +", topLevelStatement, "i"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestLabeledStatement() + [Theory, CombinatorialData] + public async Task TestLabeledStatement(bool topLevelStatement) { - await TestTryDoAsync(@" + if (!topLevelStatement) + { + await TestTryDoAsync(@" class Class { void Method() @@ -194,92 +228,63 @@ void Method() label2$$: i++; } }", "i", "this"); + } + + await TestTryDoInMainAsync(@"label: int i = 3; +label2$$: i++; +", topLevelStatement, "i"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestThrowStatement() + [Theory, CombinatorialData] + public async Task TestThrowStatement(bool topLevelStatement) { - await TestTryDoAsync(@" -class Class -{ - static void Method() - { - e = new Exception(); - thr$$ow e; - } -}", "e"); + await TestTryDoInMainAsync(@"e = new Exception(); +thr$$ow e; +", topLevelStatement, "e"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestDoStatement() + [Theory, CombinatorialData] + public async Task TestDoStatement(bool topLevelStatement) { - await TestTryDoAsync(@" -class Class -{ - static void Method() - { - do$$ { } while (true); - } -}"); + await TestTryDoInMainAsync(@"do$$ { } while (true); +", topLevelStatement, "args"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestLockStatement() + [Theory, CombinatorialData] + public async Task TestLockStatement(bool topLevelStatement) { - await TestTryDoAsync(@" -class Class -{ - static void Method() - { - lock(typeof(Cl$$ass)) { }; - } -}"); + await TestTryDoInMainAsync(@"lock(typeof(Cl$$ass)) { }; +", topLevelStatement, "args"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestWhileStatement() + [Theory, CombinatorialData] + public async Task TestWhileStatement(bool topLevelStatement) { - await TestTryDoAsync(@" -class Class -{ - static void Method() - { - while(DateTime.Now <$$ DateTime.Now) { }; - } -}", "DateTime", "DateTime.Now"); + await TestTryDoInMainAsync(@"while(DateTime.Now <$$ DateTime.Now) { }; +", topLevelStatement, "DateTime", "DateTime.Now", "args"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestForStatementWithDeclarators() + [Theory, CombinatorialData] + public async Task TestForStatementWithDeclarators(bool topLevelStatement) { - await TestTryDoAsync(@" -class Class -{ - static void Method() - { - for(int i = 0; i < 10; i$$++) { } - } -}", "i"); + await TestTryDoInMainAsync(@"for(int i = 0; i < 10; i$$++) { } +", topLevelStatement, "i", "args"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestForStatementWithInitializers() + [Theory, CombinatorialData] + public async Task TestForStatementWithInitializers(bool topLevelStatement) { - await TestTryDoAsync(@" -class Class -{ - static void Method() - { - int i = 0; - for(i = 1; i < 10; i$$++) { } - } -}", "i"); + await TestTryDoInMainAsync(@"int i = 0; +for(i = 1; i < 10; i$$++) { } +", topLevelStatement, "i"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestUsingStatement() + [Theory, CombinatorialData] + public async Task TestUsingStatement(bool topLevelStatement) { - await TestTryDoAsync(@" + if (!topLevelStatement) + { + await TestTryDoAsync(@" class Class { void Method() @@ -287,9 +292,13 @@ void Method() using (FileStream fs = new FileStream($$)) { } } }", "this"); + } + + await TestTryDoInMainAsync(@"using (FileStream fs = new FileStream($$)) { } +", topLevelStatement, "args"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] [WorkItem(538879, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538879")] public async Task TestValueInPropertySetter() { @@ -304,7 +313,7 @@ string Name }", "this", "value"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] [WorkItem(48504, "https://github.com/dotnet/roslyn/issues/48504")] public async Task TestValueInPropertyInit() { @@ -319,7 +328,7 @@ string Name }", "this", "value"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestValueInEventAdd() { await TestTryDoAsync(@" @@ -333,7 +342,7 @@ event Action Event }", "this", "value"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task TestValueInEventRemove() { await TestTryDoAsync(@" @@ -347,7 +356,7 @@ event Action Event }", "this", "value"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] [WorkItem(538880, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538880")] public async Task TestValueInIndexerSetter() { @@ -362,11 +371,13 @@ string this[int index] }", "index", "this", "value"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Theory, CombinatorialData] [WorkItem(538881, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538881")] - public async Task TestCatchBlock() + public async Task TestCatchBlock(bool topLevelStatement) { - await TestTryDoAsync(@" + if (!topLevelStatement) + { + await TestTryDoAsync(@" class Class { void Method() @@ -375,13 +386,20 @@ void Method() catch(Exception ex) { int $$ } } }", "ex", "this"); + } + + await TestTryDoInMainAsync(@"try { } +catch(Exception ex) { int $$ } +", topLevelStatement, "ex"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Theory, CombinatorialData] [WorkItem(538881, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538881")] - public async Task TestCatchBlockEmpty_OpenBrace() + public async Task TestCatchBlockEmpty_OpenBrace(bool topLevelStatement) { - await TestTryDoAsync(@" + if (!topLevelStatement) + { + await TestTryDoAsync(@" class Class { void Method() @@ -390,12 +408,19 @@ void Method() catch(Exception ex) { $$ } } }", "ex", "this"); + } + + await TestTryDoInMainAsync(@"try { } +catch(Exception ex) { $$ } +", topLevelStatement, "ex"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task TestCatchBlockEmpty_CloseBrace() + [Theory, CombinatorialData] + public async Task TestCatchBlockEmpty_CloseBrace(bool topLevelStatement) { - await TestTryDoAsync(@" + if (!topLevelStatement) + { + await TestTryDoAsync(@" class Class { void Method() @@ -404,13 +429,20 @@ void Method() catch(Exception ex) { } $$ } }", "this"); + } + + await TestTryDoInMainAsync(@"try { } +catch(Exception ex) { } $$ +", topLevelStatement); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Theory, CombinatorialData] [WorkItem(538874, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538874")] - public async Task TestObjectCreation() + public async Task TestObjectCreation(bool topLevelStatement) { - await TestTryDoAsync(@" + if (!topLevelStatement) + { + await TestTryDoAsync(@" class Class { void Method() @@ -418,9 +450,13 @@ void Method() $$Goo(new Bar(a).Baz); } }", "a", "new Bar(a).Baz", "Goo", "this"); + } + + await TestTryDoInMainAsync(@"$$Goo(new Bar(a).Baz); +", topLevelStatement, "a", "new Bar(a).Baz", "Goo", "args"); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] [WorkItem(538874, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538874")] public async Task Test2() { @@ -439,7 +475,7 @@ void Method() }", "D.x", false); } - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] [WorkItem(538890, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538890")] public async Task TestArrayCreation() { @@ -455,7 +491,7 @@ void Method() } [WorkItem(751141, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/751141")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] + [Fact] public async Task Bug751141() { await TestTryDoAsync(@" @@ -476,460 +512,365 @@ void M() } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ForLoopExpressionsInFirstStatementOfLoop1() + [Theory, CombinatorialData] + public async Task ForLoopExpressionsInFirstStatementOfLoop1(bool topLevelStatement) { - await TestTryDoAsync(@"class Program + await TestTryDoInMainAsync(@"for(int i = 0; i < 5; i++) { - static void Main(string[] args) - { - for(int i = 0; i < 5; i++) - { - $$var x = 8; - } - } -}", "i", "x"); + $$var x = 8; +} +", topLevelStatement, "i", "x"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ForLoopExpressionsInFirstStatementOfLoop2() + [Theory, CombinatorialData] + public async Task ForLoopExpressionsInFirstStatementOfLoop2(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int i = 0, j = 0, k = 0, m = 0, n = 0; + await TestTryDoInMainAsync(@"int i = 0, j = 0, k = 0, m = 0, n = 0; - for(i = 0; j < 5; k++) - { - $$m = 8; - n = 7; - } - } -}", "m", "i", "j", "k"); +for(i = 0; j < 5; k++) +{ + $$m = 8; + n = 7; +} +", topLevelStatement, "m", "i", "j", "k"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ForLoopExpressionsInFirstStatementOfLoop3() + [Theory, CombinatorialData] + public async Task ForLoopExpressionsInFirstStatementOfLoop3(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int i = 0, j = 0, k = 0, m = 0; + await TestTryDoInMainAsync(@"int i = 0, j = 0, k = 0, m = 0; - for(i = 0; j < 5; k++) - { - var m = 8; - $$var n = 7; - } - } -}", "m", "n"); +for(i = 0; j < 5; k++) +{ + var m = 8; + $$var n = 7; +} +", topLevelStatement, "m", "n"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ForLoopExpressionsInFirstStatementOfLoop4() + [Theory, CombinatorialData] + public async Task ForLoopExpressionsInFirstStatementOfLoop4(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int i = 0, j = 0, k = 0, m = 0; + await TestTryDoInMainAsync(@"int i = 0, j = 0, k = 0, m = 0; - for(i = 0; j < 5; k++) - $$m = 8; - } -}", "m", "i", "j", "k"); +for(i = 0; j < 5; k++) + $$m = 8; +", topLevelStatement, "m", "i", "j", "k"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ForEachLoopExpressionsInFirstStatementOfLoop1() + [Theory, CombinatorialData] + public async Task ForEachLoopExpressionsInFirstStatementOfLoop1(bool topLevelStatement) { - await TestTryDoAsync(@"class Program + await TestTryDoInMainAsync(@"foreach (var x in new int[] { 1, 2, 3 }) { - static void Main(string[] args) - { - foreach (var x in new int[] { 1, 2, 3 }) - { - $$var z = 0; - } - } -}", "x", "z"); + $$var z = 0; +} +", topLevelStatement, "x", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ForEachLoopExpressionsInFirstStatementOfLoop2() + [Theory, CombinatorialData] + public async Task ForEachLoopExpressionsInFirstStatementOfLoop2(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - foreach (var x in new int[] { 1, 2, 3 }) - $$var z = 0; - } -}", "x", "z"); + await TestTryDoInMainAsync(@"foreach (var x in new int[] { 1, 2, 3 }) + $$var z = 0; +", topLevelStatement, "x", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterForLoop1() + [Theory, CombinatorialData] + public async Task ExpressionsAfterForLoop1(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0; - for (a = 5; b < 1; b++) - { - c = 8; - d = 9; // included - } +for (a = 5; b < 1; b++) +{ + c = 8; + d = 9; // included +} - $$var z = 0; - } -}", "a", "b", "d", "z"); +$$var z = 0; +", topLevelStatement, "a", "b", "d", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterForLoop2() + [Theory, CombinatorialData] + public async Task ExpressionsAfterForLoop2(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0; - for (a = 5; b < 1; b++) - { - c = 8; - int d = 9; // not included - } +for (a = 5; b < 1; b++) +{ + c = 8; + int d = 9; // not included +} - $$var z = 0; - } -}", "a", "b", "z"); +$$var z = 0; +", topLevelStatement, "a", "b", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterForEachLoop() + [Theory, CombinatorialData] + public async Task ExpressionsAfterForEachLoop(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0; - foreach (var q in new int[] {1, 2, 3}) - { - c = 8; - d = 9; // included - } +foreach (var q in new int[] {1, 2, 3}) +{ + c = 8; + d = 9; // included +} - $$var z = 0; - } -}", "q", "d", "z"); +$$var z = 0; +", topLevelStatement, "q", "d", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterNestedForLoop() + [Theory, CombinatorialData] + public async Task ExpressionsAfterNestedForLoop(bool topLevelStatement) { - await TestTryDoAsync(@"class Program + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; + +for (a = 5; b < 1; b++) { - static void Main(string[] args) + c = 8; + d = 9; + for (a = 7; b < 9; b--) { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; - - for (a = 5; b < 1; b++) - { - c = 8; - d = 9; - for (a = 7; b < 9; b--) - { - e = 8; - f = 10; // included - } - } - - $$var z = 0; + e = 8; + f = 10; // included } -}", "a", "b", "f", "z"); +} + +$$var z = 0; +", topLevelStatement, "a", "b", "f", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterCheckedStatement() + [Theory, CombinatorialData] + public async Task ExpressionsAfterCheckedStatement(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; - checked - { - a = 7; - b = 0; // included - } +checked +{ + a = 7; + b = 0; // included +} - $$var z = 0; - } -}", "b", "z"); +$$var z = 0; +", topLevelStatement, "b", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterUncheckedStatement() + [Theory, CombinatorialData] + public async Task ExpressionsAfterUncheckedStatement(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; - unchecked - { - a = 7; - b = 0; // included - } +unchecked +{ + a = 7; + b = 0; // included +} - $$var z = 0; - } -}", "b", "z"); +$$var z = 0; +", topLevelStatement, "b", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterIfStatement() + [Theory, CombinatorialData] + public async Task ExpressionsAfterIfStatement(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; - if (a == 0) - { - c = 8; - d = 9; // included - } +if (a == 0) +{ + c = 8; + d = 9; // included +} - $$var z = 0; - } -}", "a", "d", "z"); +$$var z = 0; +", topLevelStatement, "a", "d", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterIfStatementWithElse() + [Theory, CombinatorialData] + public async Task ExpressionsAfterIfStatementWithElse(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; - if (a == 0) - { - c = 8; - d = 9; // included - } - else - { - e = 1; - f = 2; // included - } +if (a == 0) +{ + c = 8; + d = 9; // included +} +else +{ + e = 1; + f = 2; // included +} - $$var z = 0; - } -}", "a", "d", "f", "z"); +$$var z = 0; +", topLevelStatement, "a", "d", "f", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterLockStatement() + [Theory, CombinatorialData] + public async Task ExpressionsAfterLockStatement(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; - lock (new object()) - { - a = 2; - b = 3; // included - } +lock (new object()) +{ + a = 2; + b = 3; // included +} - $$var z = 0; - } -}", "b", "z"); +$$var z = 0; +", topLevelStatement, "b", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterSwitchStatement() - { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; - - switch(a) - { - case 1: - b = 7; - c = 8; // included - break; - case 2: - d = 9; - e = 10; // included - break; - default: - f = 1; - g = 2; // included - break; - } + [Theory, CombinatorialData] + public async Task ExpressionsAfterSwitchStatement(bool topLevelStatement) + { + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; + +switch(a) +{ + case 1: + b = 7; + c = 8; // included + break; + case 2: + d = 9; + e = 10; // included + break; + default: + f = 1; + g = 2; // included + break; +} - $$var z = 0; - } -}", "a", "c", "e", "g", "z"); +$$var z = 0; +", topLevelStatement, "a", "c", "e", "g", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterTryStatement() + [Theory, CombinatorialData] + public async Task ExpressionsAfterTryStatement(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; - try - { - a = 2; - b = 3; // included - } - catch (System.DivideByZeroException) - { - c = 2; - d = 5; // included - } - catch (System.EntryPointNotFoundException) - { - e = 8; - f = 9; // included - } +try +{ + a = 2; + b = 3; // included +} +catch (System.DivideByZeroException) +{ + c = 2; + d = 5; // included +} +catch (System.EntryPointNotFoundException) +{ + e = 8; + f = 9; // included +} - $$var z = 0; - } -}", "b", "d", "f", "z"); +$$var z = 0; +", topLevelStatement, "b", "d", "f", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterTryStatementWithFinally() + [Theory, CombinatorialData] + public async Task ExpressionsAfterTryStatementWithFinally(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; - try - { - a = 2; - b = 3; - } - catch (System.DivideByZeroException) - { - c = 2; - d = 5; - } - catch (System.EntryPointNotFoundException) - { - e = 8; - f = 9; - } - finally - { - g = 2; // included - } +try +{ + a = 2; + b = 3; +} +catch (System.DivideByZeroException) +{ + c = 2; + d = 5; +} +catch (System.EntryPointNotFoundException) +{ + e = 8; + f = 9; +} +finally +{ + g = 2; // included +} - $$var z = 0; - } -}", "g", "z"); +$$var z = 0; +", topLevelStatement, "g", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterUsingStatement() + [Theory, CombinatorialData] + public async Task ExpressionsAfterUsingStatement(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; - using (null as System.IDisposable) - { - a = 4; - b = 8; // Included - } +using (null as System.IDisposable) +{ + a = 4; + b = 8; // Included +} - $$var z = 0; - } -}", "b", "z"); +$$var z = 0; +", topLevelStatement, "b", "z"); } [WorkItem(775161, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/775161")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsAfterWhileStatement() + [Theory, CombinatorialData] + public async Task ExpressionsAfterWhileStatement(bool topLevelStatement) { - await TestTryDoAsync(@"class Program -{ - static void Main(string[] args) - { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; + await TestTryDoInMainAsync(@"int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; - while (a < 5) - { - a++; - b = 8; // Included - } +while (a < 5) +{ + a++; + b = 8; // Included +} - $$var z = 0; - } -}", "a", "b", "z"); +$$var z = 0; +", topLevelStatement, "a", "b", "z"); } [WorkItem(778215, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/778215")] - [Fact, Trait(Traits.Feature, Traits.Features.DebuggingProximityExpressions)] - public async Task ExpressionsInParenthesizedExpressions() + [Theory, CombinatorialData] + public async Task ExpressionsInParenthesizedExpressions(bool topLevelStatement) { - await TestTryDoAsync(@"class Program + await TestTryDoInMainAsync(@"int i = 0, j = 0, k = 0, m = 0; +int flags = 7; + +if((flags & i) == k) { - static void Main(string[] args) - { - int i = 0, j = 0, k = 0, m = 0; - int flags = 7; + $$ m = 8; +} +", topLevelStatement, "m", "flags", "i", "k"); + } - if((flags & i) == k) + [WorkItem(58337, "https://github.com/dotnet/roslyn/issues/58337")] + [Theory, CombinatorialData] + public async Task ExpressionsInTopLevelStatement(bool topLevelStatement) { - $$ m = 8; - } - } -}", "m", "flags", "i", "k"); + await TestTryDoInMainAsync(@"int a = 1; +int b = 2; +$$ Console.WriteLine(""Hello, World!""); +", topLevelStatement, "Console", "b"); } } } diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/Configuration/ConfigureSeverity/DotNetDiagnosticSeverityBasedSeverityConfigurationTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/Configuration/ConfigureSeverity/DotNetDiagnosticSeverityBasedSeverityConfigurationTests.cs index f29df8f347c07..967585dba31da 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/Configuration/ConfigureSeverity/DotNetDiagnosticSeverityBasedSeverityConfigurationTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/Configuration/ConfigureSeverity/DotNetDiagnosticSeverityBasedSeverityConfigurationTests.cs @@ -295,6 +295,101 @@ class Program1 { } [*.cs] +# XYZ0001: Title +dotnet_diagnostic.XYZ0001.severity = none + + +"; + + await TestInRegularAndScriptAsync(input, expected, CodeActionIndex); + } + + [ConditionalFact(typeof(IsEnglishLocal)), Trait(Traits.Feature, Traits.Features.CodeActionsConfiguration)] + public async Task ConfigureGlobalconfig_Empty_None() + { + var input = @" + + + +[|class Program1 { }|] + + is_global = true + +"; + + var expected = @" + + + +class Program1 { } + + is_global = true + +# XYZ0001: Title +dotnet_diagnostic.XYZ0001.severity = none + + +"; + + await TestInRegularAndScriptAsync(input, expected, CodeActionIndex); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConfiguration)] + public async Task ConfigureGlobalconfig_RuleExists_None() + { + var input = @" + + + +[|class Program1 { }|] + + is_global = true # Comment +dotnet_diagnostic.XYZ0001.severity = suggestion # Comment + + +"; + + var expected = @" + + + +class Program1 { } + + is_global = true # Comment +dotnet_diagnostic.XYZ0001.severity = none # Comment + + +"; + + await TestInRegularAndScriptAsync(input, expected, CodeActionIndex); + } + + [ConditionalFact(typeof(IsEnglishLocal)), Trait(Traits.Feature, Traits.Features.CodeActionsConfiguration)] + public async Task ConfigureGlobalconfig_InvalidHeader_None() + { + var input = @" + + + +[|class Program1 { }|] + + [*.vb] +dotnet_diagnostic.XYZ0001.severity = suggestion + + +"; + + var expected = @" + + + +class Program1 { } + + [*.vb] +dotnet_diagnostic.XYZ0001.severity = suggestion + +[*.cs] + # XYZ0001: Title dotnet_diagnostic.XYZ0001.severity = none diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs index 767cc14c124f1..9294ae9a342c0 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs @@ -170,7 +170,7 @@ public async Task AnalyzerOptionsArePassedToAllAnalyzers() workspace.TryApplyChanges(workspace.CurrentSolution .WithAnalyzerReferences(new[] { analyzerReference }) - .AddAdditionalDocument(additionalDocId, "add.config", additionalText.GetText())); + .AddAdditionalDocument(additionalDocId, "add.config", additionalText.GetText()!)); var sourceDocument = workspace.CurrentSolution.Projects.Single().Documents.Single(); await DiagnosticProviderTestUtilities.GetAllDiagnosticsAsync(workspace, sourceDocument, new TextSpan(0, sourceDocument.GetTextAsync().Result.Length)); diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/FixReturnType/FixReturnTypeTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/FixReturnType/FixReturnTypeTests.cs index ef8a7fe039cb8..a8ec7e99295cb 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/FixReturnType/FixReturnTypeTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/FixReturnType/FixReturnTypeTests.cs @@ -309,6 +309,48 @@ void M() { return Console.WriteLine()[||]; } +}"); + } + + [Fact] + [WorkItem(53574, "https://github.com/dotnet/roslyn/issues/53574")] + public async Task TestAnonymousTypeTopLevel() + { + await TestInRegularAndScript1Async( +@"class C +{ + public void Method() + { + [|return|] new { A = 0, B = 1 }; + } +}", +@"class C +{ + public object Method() + { + return new { A = 0, B = 1 }; + } +}"); + } + + [Fact] + [WorkItem(53574, "https://github.com/dotnet/roslyn/issues/53574")] + public async Task TestAnonymousTypeTopNested() + { + await TestInRegularAndScript1Async( +@"class C +{ + public void Method() + { + [|return|] new[] { new { A = 0, B = 1 } }; + } +}", +@"class C +{ + public object Method() + { + return new[] { new { A = 0, B = 1 } }; + } }"); } } diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/GenerateMethod/GenerateMethodTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateMethod/GenerateMethodTests.cs index 6da438b264dca..1932f6c1aa04f 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/GenerateMethod/GenerateMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateMethod/GenerateMethodTests.cs @@ -9130,5 +9130,81 @@ internal static void Method() } "); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)] + public async Task TestInSwitchExpression1() + { + await TestInRegularAndScriptAsync( +@" +using System; + +class Class +{ + string Method(int i) + { + return i switch + { + 0 => [|Goo|](), + }; + } +}", +@" +using System; + +class Class +{ + string Method(int i) + { + return i switch + { + 0 => Goo(), + }; + } + + private string Goo() + { + throw new NotImplementedException(); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)] + public async Task TestInSwitchExpression2() + { + await TestInRegularAndScriptAsync( +@" +using System; + +class Class +{ + void Method(int i) + { + var v = i switch + { + 0 => """", + 1 => [|Goo|](), + }; + } +}", +@" +using System; + +class Class +{ + void Method(int i) + { + var v = i switch + { + 0 => """", + 1 => Goo(), + }; + } + + private string Goo() + { + throw new NotImplementedException(); + } +}"); + } } } diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs index 751725372992f..56a5df86e2ee6 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs @@ -6,7 +6,7 @@ using System.Collections.Immutable; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeStyle; diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/MockDiagnosticAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/MockDiagnosticAnalyzerTests.cs index d9843e132cf6f..f612f0343c681 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/MockDiagnosticAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/MockDiagnosticAnalyzerTests.cs @@ -21,7 +21,7 @@ public partial class MockDiagnosticAnalyzerTests : AbstractCSharpDiagnosticProvi private class MockDiagnosticAnalyzer : DiagnosticAnalyzer { public const string Id = "MockDiagnostic"; - private readonly DiagnosticDescriptor _descriptor = new DiagnosticDescriptor(Id, "MockDiagnostic", "MockDiagnostic", "InternalCategory", DiagnosticSeverity.Warning, isEnabledByDefault: true); + private readonly DiagnosticDescriptor _descriptor = new DiagnosticDescriptor(Id, "MockDiagnostic", "MockDiagnostic", "InternalCategory", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: "https://github.com/dotnet/roslyn"); public override ImmutableArray SupportedDiagnostics { diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs index b4a447b71d4d5..2e7fffcbd1bda 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs @@ -467,7 +467,8 @@ void Method() var diagnostics = await diagnosticService.GetDiagnosticsForSpanAsync(document, span); Assert.Equal(2, diagnostics.Where(d => d.Id == "CS0219").Count()); - var allFixes = (await fixService.GetFixesAsync(document, span, cancellationToken: CancellationToken.None)) + var options = CodeActionOptions.Default; + var allFixes = (await fixService.GetFixesAsync(document, span, options, CancellationToken.None)) .SelectMany(fixCollection => fixCollection.Fixes); var cs0219Fixes = allFixes.Where(fix => fix.PrimaryDiagnostic.Id == "CS0219").ToArray(); diff --git a/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs b/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs index c03108654b299..e5515ce20e2c8 100644 --- a/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs +++ b/src/EditorFeatures/CSharpTest/DocumentationComments/DocumentationCommentTests.cs @@ -706,6 +706,48 @@ public void TypingCharacter_NotInsideCtor() VerifyTypingCharacter(code, expected); } + [WorkItem(59081, "https://github.com/dotnet/roslyn/issues/59081")] + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentationComments)] + public void TypingCharacter_NotInTopLevel() + { + var code = @" +using System; + +//$$ +Console.WriteLine(); +"; + + var expected = @" +using System; + +///$$ +Console.WriteLine(); +"; + + VerifyTypingCharacter(code, expected); + } + + [WorkItem(59081, "https://github.com/dotnet/roslyn/issues/59081")] + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentationComments)] + public void TypingCharacter_NotInNamespace() + { + var code = @" +using System; + +//$$ +namespace NS { } +"; + + var expected = @" +using System; + +///$$ +namespace NS { } +"; + + VerifyTypingCharacter(code, expected); + } + [WpfFact, Trait(Traits.Feature, Traits.Features.DocumentationComments)] public void PressingEnter_InsertComment_Class1() { diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs index b0b9c401a3b0b..40d86f0a6ea03 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs @@ -11221,13 +11221,13 @@ public static void H(int x) { if (node.Parent is MethodDeclarationSyntax methodDecl && methodDecl.Identifier.Text == "G") { - throw outOfMemory ? new OutOfMemoryException() : new NullReferenceException("NullRef!"); + throw outOfMemory ? new OutOfMemoryException() : new SimpleToStringException(); } }); var expectedDiagnostic = outOfMemory ? Diagnostic(RudeEditKind.MemberBodyTooBig, "public static void G()", FeaturesResources.method) : - Diagnostic(RudeEditKind.MemberBodyInternalError, "public static void G()", FeaturesResources.method); + Diagnostic(RudeEditKind.MemberBodyInternalError, "public static void G()", FeaturesResources.method, SimpleToStringException.ToStringOutput); validator.VerifySemantics( new[] { edits }, @@ -11235,6 +11235,20 @@ public static void H(int x) new[] { DocumentResults(diagnostics: new[] { expectedDiagnostic }) }); } + /// + /// Custom exception class that has a fixed ToString so that tests aren't relying + /// on stack traces, which could make them flaky + /// + private class SimpleToStringException : Exception + { + public const string ToStringOutput = ""; + + public override string ToString() + { + return ToStringOutput; + } + } + #endregion #region Top Level Statements diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs index a0ff1d20dff26..b8184f7eb6af4 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs @@ -100,7 +100,7 @@ static void Goo() new[] { new SourceLineUpdate(4, 9), - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(7), + new SourceLineUpdate(7, 7), new SourceLineUpdate(9, 4) }); } @@ -151,9 +151,9 @@ static int Bar() new[] { new SourceLineUpdate(4, 9), - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(8), + new SourceLineUpdate(8, 8), new SourceLineUpdate(10, 4), - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(13), + new SourceLineUpdate(13, 13), }); } @@ -318,7 +318,7 @@ class C new[] { new SourceLineUpdate(3, 4), - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(4) + new SourceLineUpdate(4, 4) }); } @@ -598,7 +598,7 @@ public C(int a) new[] { new SourceLineUpdate(4, 8), - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(6), + new SourceLineUpdate(6, 6), new SourceLineUpdate(8, 4) }); } @@ -1793,7 +1793,7 @@ class C new[] { new SourceLineUpdate(3, 9), - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(5), + new SourceLineUpdate(5, 5), new SourceLineUpdate(9, 3) }); } @@ -1885,10 +1885,10 @@ void F4() {} edits.VerifyLineEdits( new SequencePointUpdates[] { - new("a", ImmutableArray.Create( - new(2, 12), // x, y, F1, F2 - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(6), // lines between F2 and D ctor - new(9, 19))) // D ctor + new("a", ImmutableArray.Create( + new SourceLineUpdate(2, 12), // x, y, F1, F2 + new SourceLineUpdate(6, 6), // lines between F2 and D ctor + new SourceLineUpdate(9, 19))) // D ctor }, semanticEdits: new[] { diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs index ee4df8c5e2fa4..571d1e4f31a97 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -7314,9 +7314,9 @@ static void F() targetFrameworks: new[] { TargetFramework.NetCoreApp }, expectedDiagnostics: new[] { - Diagnostic(RudeEditKind.InsertLocalFunctionIntoInterfaceMethod, "f1"), - Diagnostic(RudeEditKind.InsertLocalFunctionIntoInterfaceMethod, "f2"), - Diagnostic(RudeEditKind.InsertLocalFunctionIntoInterfaceMethod, "f3") + Diagnostic(RudeEditKind.InsertLocalFunctionIntoInterfaceMethod, "f1", CSharpFeaturesResources.local_function), + Diagnostic(RudeEditKind.InsertLocalFunctionIntoInterfaceMethod, "f2", CSharpFeaturesResources.local_function), + Diagnostic(RudeEditKind.InsertLocalFunctionIntoInterfaceMethod, "f3", CSharpFeaturesResources.local_function) }); } diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs index 80c91463c1733..9d222a586b960 100644 --- a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs @@ -5,7 +5,7 @@ using System; using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/JsonStringDetectorTests.cs b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/JsonStringDetectorTests.cs new file mode 100644 index 0000000000000..48c3e36c8967c --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/JsonStringDetectorTests.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.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EmbeddedLanguages +{ + using VerifyCS = CSharpCodeFixVerifier< + CSharpJsonDetectionAnalyzer, + CSharpJsonDetectionCodeFixProvider>; + + public class JsonStringDetectorTests + { + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsDetectJsonString)] + public async Task TestStrict() + { + await new VerifyCS.Test + { + TestCode = +@" +class C +{ + void Goo() + { + var j = [|""{ \""a\"": 0 }""|]; + } +}", + FixedCode = +@" +class C +{ + void Goo() + { + var j = /*lang=json,strict*/ ""{ \""a\"": 0 }""; + } +}", + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsDetectJsonString)] + public async Task TestNonStrict() + { + await new VerifyCS.Test + { + TestCode = +@" +class C +{ + void Goo() + { + var j = [|""{ 'a': 00 }""|]; + } +}", + FixedCode = +@" +class C +{ + void Goo() + { + var j = /*lang=json*/ ""{ 'a': 00 }""; + } +}", + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsDetectJsonString)] + public async Task TestNonStrictRawString() + { + await new VerifyCS.Test + { + TestCode = +@" +class C +{ + void Goo() + { + var j = [|""""""{ 'a': 00 }""""""|]; + } +}", + FixedCode = +@" +class C +{ + void Goo() + { + var j = /*lang=json*/ """"""{ 'a': 00 }""""""; + } +}", + LanguageVersion = LanguageVersion.Preview, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsDetectJsonString)] + public async Task TestNotWithExistingComment() + { + var code = @" +class C +{ + void Goo() + { + var j = /*lang=json,strict*/ ""{ \""a\"": 0 }""; + } +}"; + await new VerifyCS.Test + { + TestCode = code, + FixedCode = code, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsDetectJsonString)] + public async Task TestNotOnUnlikelyJson() + { + var code = @" +class C +{ + void Goo() + { + var j = ""[1, 2, 3]""; + } +}"; + await new VerifyCS.Test + { + TestCode = code, + FixedCode = code, + }.RunAsync(); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs new file mode 100644 index 0000000000000..33eb5b41b702a --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs @@ -0,0 +1,398 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities.EmbeddedLanguages; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EmbeddedLanguages +{ + public class ValidateJsonStringTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest + { + public ValidateJsonStringTests(ITestOutputHelper logger) : base(logger) + { + } + + internal override (DiagnosticAnalyzer, CodeFixProvider?) CreateDiagnosticProviderAndFixer(Workspace workspace) + => (new CSharpJsonDiagnosticAnalyzer(), null); + + private static OptionsCollection OptionOn() + => new(LanguageNames.CSharp) + { + { JsonFeatureOptions.ReportInvalidJsonPatterns, true } + }; + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestWarning1() + { + await TestDiagnosticInfoAsync(@" +class Program +{ + void Main() + { + var r = /*lang=json,strict*/ ""[|new|] Json()""; + } +}", + options: OptionOn(), + diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Warning, + diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, FeaturesResources.Constructors_not_allowed)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestWarningInRawString1() + { + await TestDiagnosticInfoAsync(@" +class Program +{ + void Main() + { + var r = /*lang=json,strict*/ """"""[|new|] Json()""""""; + } +}", + options: OptionOn(), + diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Warning, + diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, FeaturesResources.Constructors_not_allowed)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestWarning2() + { + await TestDiagnosticInfoAsync(@" +class Program +{ + void Main() + { + var r = /*lang=json*/ ""[|}|]""; + } +}", + options: OptionOn(), + diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Warning, + diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, + string.Format(FeaturesResources._0_unexpected, '}'))); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentWithTrailingComma() + { + await TestDiagnosticInfoAsync(@" + + +using System.Text.Json; + +class Program +{ + void Main() + { + var r = JsonDocument.Parse(@""[1[|,|]]""); + } +} + + +", + options: OptionOn(), + diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Warning, + diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Trailing_comma_not_allowed)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentTrailingCommaDisallowed() + { + await TestDiagnosticInfoAsync(@" + + +using System.Text.Json; + +class Program +{ + void Main() + { + var r = JsonDocument.Parse(@""[1[|,|]]"", new JsonDocumentOptions { AllowTrailingCommas = false }); + } +} + + +", + options: OptionOn(), + diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Warning, + diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Trailing_comma_not_allowed)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentTrailingCommaAllowed() + { + await TestDiagnosticMissingAsync(@" + + +using System.Text.Json; + +class Program +{ + void Main() + { + var r = JsonDocument.Parse(@""[1[|,|]]"", new JsonDocumentOptions { AllowTrailingCommas = true }); + } +} + + +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentTrailingCommaAllowedImplicitObject() + { + await TestDiagnosticMissingAsync(@" + + +using System.Text.Json; + +class Program +{ + void Main() + { + var r = JsonDocument.Parse(@""[1[|,|]]"", new() { AllowTrailingCommas = true }); + } +} + + +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentWithComments() + { + await TestDiagnosticInfoAsync(@" + + +using System.Text.Json; + +class Program +{ + void Main() + { + var r = JsonDocument.Parse(@""[1][|/*comment*/|]""); + } +} + + +", + options: OptionOn(), + diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Warning, + diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Comments_not_allowed)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentCommentsDisallowed() + { + await TestDiagnosticInfoAsync(@" + + +using System.Text.Json; + +class Program +{ + void Main() + { + var r = JsonDocument.Parse(@""[1][|/*comment*/|]"", new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Disallow }); + } +} + + +", + options: OptionOn(), + diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Warning, + diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Comments_not_allowed)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentCommentsAllowed() + { + await TestDiagnosticMissingAsync(@" + + +using System.Text.Json; + +class Program +{ + void Main() + { + var r = JsonDocument.Parse(@""[1][|/*comment*/|]"", new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Allow }); + } +} + + +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentCommentsAllowedImplicitObject() + { + await TestDiagnosticMissingAsync(@" + + +using System.Text.Json; + +class Program +{ + void Main() + { + var r = JsonDocument.Parse(@""[1][|/*comment*/|]"", new() { CommentHandling = JsonCommentHandling.Allow }); + } +} + + +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentCommentsDisallowed_StringSyntaxAttribute_NoOptionsProvided() + { + await TestDiagnosticInfoAsync($@" + + +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; + +class Program +{{ + void Main() + {{ + M(@""[1][|/*comment*/|]""); + }} + + void M([StringSyntax(StringSyntaxAttribute.Json)] string p) + {{ + }} +}} +{EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharpXml} + + +", + options: OptionOn(), + diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Warning, + diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Comments_not_allowed)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentCommentsDisallowed_StringSyntaxAttribute_OptionsProvided() + { + await TestDiagnosticInfoAsync($@" + + +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; + +class Program +{{ + void Main() + {{ + M(@""[1][|/*comment*/|]"", new JsonDocumentOptions {{ CommentHandling = JsonCommentHandling.Disallow }}); + }} + + void M([StringSyntax(StringSyntaxAttribute.Json)] string p, JsonDocumentOptions options) + {{ + }} +}} +{EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharpXml} + + +", + options: OptionOn(), + diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Warning, + diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Comments_not_allowed)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestJsonDocumentCommentsAllowed_StringSyntaxAttribute_OptionsProvided() + { + await TestDiagnosticMissingAsync($@" + + +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; + +class Program +{{ + void Main() + {{ + M(@""[1][|/*comment*/|]"", new JsonDocumentOptions {{ CommentHandling = JsonCommentHandling.Allow }}); + }} + + void M([StringSyntax(StringSyntaxAttribute.Json)] string p, JsonDocumentOptions options) + {{ + }} +}} +{EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharpXml} + + +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestNotOnUnlikelyJson() + { + await TestDiagnosticMissingAsync($@" + + + +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; + +class Program +{{ + void Main() + {{ + var v = [|""[1, 2, 3]""|]; + }} +}} + + +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] + public async Task TestNotOnLikelyJson() + { + await TestDiagnosticMissingAsync($@" + + + +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; + +class Program +{{ + void Main() + {{ + var v = [|""{{ prop: 0 }}""|]; + }} +}} + + +"); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateRegexStringTests.cs b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateRegexStringTests.cs index e8f2c0ff9b963..2617c7eba0194 100644 --- a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateRegexStringTests.cs +++ b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateRegexStringTests.cs @@ -2,16 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; -using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; -using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -25,15 +22,14 @@ public ValidateRegexStringTests(ITestOutputHelper logger) { } - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) + internal override (DiagnosticAnalyzer, CodeFixProvider?) CreateDiagnosticProviderAndFixer(Workspace workspace) => (new CSharpRegexDiagnosticAnalyzer(), null); private static OptionsCollection OptionOn() - { - var optionsSet = new OptionsCollection(LanguageNames.CSharp); - optionsSet.Add(RegularExpressionsOptions.ReportInvalidRegexPatterns, true); - return optionsSet; - } + => new(LanguageNames.CSharp) + { + { RegularExpressionsOptions.ReportInvalidRegexPatterns, true } + }; [Fact, Trait(Traits.Feature, Traits.Features.ValidateRegexString)] public async Task TestWarning1() diff --git a/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs b/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs index 6bcb5af3edb70..8f88801a7f0c7 100644 --- a/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs @@ -5,7 +5,9 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp; @@ -690,7 +692,7 @@ static void Main(string[] args) Options = { { CSharpCodeStyleOptions.NamespaceDeclarations, NamespaceDeclarationPreference.FileScoped, NotificationOption2.Error }, { CodeStyleOptions2.FileHeaderTemplate, "this is my real document header" }, - { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, CodeAnalysis.AddImports.AddImportPlacement.InsideNamespace } + { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, AddImportPlacement.InsideNamespace } } }.RunAsync(); } @@ -757,7 +759,7 @@ static void Main(string[] args) LanguageVersion = LanguageVersion.CSharp10, Options = { { CodeStyleOptions2.FileHeaderTemplate, "this is my real document header" }, - { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, CodeAnalysis.AddImports.AddImportPlacement.InsideNamespace } + { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, AddImportPlacement.InsideNamespace } } }.RunAsync(); } @@ -810,7 +812,7 @@ static void Main(string[] args) }, LanguageVersion = LanguageVersion.CSharp10, Options = { - { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, CodeAnalysis.AddImports.AddImportPlacement.InsideNamespace } + { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, AddImportPlacement.InsideNamespace } } }.RunAsync(); } @@ -878,7 +880,7 @@ static void Main(string[] args) }, LanguageVersion = LanguageVersion.CSharp10, Options = { - { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, CodeAnalysis.AddImports.AddImportPlacement.InsideNamespace } + { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, AddImportPlacement.InsideNamespace } } }.RunAsync(); } @@ -2043,7 +2045,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) + public Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalSymbol, ISymbol? selectedMember, CancellationToken cancellationToken) { var availableMembers = originalSymbol.GetMembers().Where(member => MemberAndDestinationValidator.IsMemberValid(member)); diff --git a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs index 363f70df875ea..f44dbb79f780c 100644 --- a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Threading.Tasks; using System.Xml.Linq; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs index b95540de7e212..bd8def4fe0906 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs @@ -11336,5 +11336,153 @@ private static IntPtr NewMethod(object value) "; await TestExtractMethodAsync(code, expected); } + + [Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)] + public async Task ExtractRawStringLiteral_SingleLine() + { + var code = @" +class C +{ + void M(int y) + { + var s = [|""""""Hello world""""""|]; + } +}"; + var expected = @" +class C +{ + void M(int y) + { + var s = GetS(); + } + + private static string GetS() + { + return """"""Hello world""""""; + } +}"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)] + public async Task ExtractRawStringLiteralInterpolation_SingleLine() + { + var code = @" +class C +{ + void M(int y) + { + var s = [|$""""""{y}""""""|]; + } +}"; + var expected = @" +class C +{ + void M(int y) + { + var s = GetS(y); + } + + private static string GetS(int y) + { + return $""""""{y}""""""; + } +}"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)] + public async Task ExtractRawStringLiteralInterpolationHole_SingleLine() + { + var code = @" +class C +{ + void M(int y) + { + var s = $""""""{[|y|]}""""""; + } +}"; + var expected = @" +class C +{ + void M(int y) + { + var s = $""""""{GetY(y)}""""""; + } + + private static int GetY(int y) + { + return y; + } +}"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)] + public async Task ExtractRawStringLiteral_MultiLine() + { + var code = @" +class C +{ + void M(int y) + { + var s = [|"""""" + Hello world + """"""|]; + } +}"; + var expected = @" +class C +{ + void M(int y) + { + var s = GetS(); + } + + private static string GetS() + { + return """""" + Hello world + """"""; + } +}"; + + await TestExtractMethodAsync(code, expected); + } + + [Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)] + public async Task ExtractRawStringLiteralInterpolation_MultiLine() + { + var code = @" +class C +{ + void M(int y) + { + var s = $[|"""""" + {y} + """"""|]; + } +}"; + var expected = @" +class C +{ + void M(int y) + { + var s = GetS(y); + } + + private static string GetS(int y) + { + return $"""""" + {y} + """"""; + } +}"; + + await TestExtractMethodAsync(code, expected); + } } } diff --git a/src/EditorFeatures/CSharpTest/Formatting/CSharpNewDocumentFormattingServiceTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CSharpNewDocumentFormattingServiceTests.cs index 12f72de194563..7db1a4fe72cec 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CSharpNewDocumentFormattingServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CSharpNewDocumentFormattingServiceTests.cs @@ -3,11 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities.Formatting; using Roslyn.Test.Utilities; using Xunit; @@ -171,6 +172,31 @@ internal class C }); } + [Fact] + public async Task TestAccessibilityModifiers_FileScopedNamespace() + { + await TestAsync(testCode: @"using System; + +namespace Goo +{ + class C + { + } +}", + expected: @"using System; + +namespace Goo; +internal class C +{ +} +", + options: new (OptionKey, object)[] + { + (new OptionKey(CSharpCodeStyleOptions.NamespaceDeclarations), new CodeStyleOption2(NamespaceDeclarationPreference.FileScoped, NotificationOption2.Error)), + (new OptionKey(CodeStyleOptions2.RequireAccessibilityModifiers, Language), new CodeStyleOption2(AccessibilityModifiersRequired.Always, NotificationOption2.Error)) + }); + } + [Fact] [WorkItem(55703, "https://github.com/dotnet/roslyn/issues/55703")] public async Task TestAccessibilityModifiers_IgnoresPartial() diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index 0d1219d77024b..5fb6fb0351e9b 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -7,7 +7,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; @@ -561,6 +562,8 @@ private protected static async Task AssertCodeCleanupResult(string expected, str { using var workspace = TestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf); + var options = CodeActionOptions.Default; + var solution = workspace.CurrentSolution .WithOptions(workspace.Options .WithChangedOption(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp, systemUsingsFirst) @@ -586,7 +589,7 @@ private protected static async Task AssertCodeCleanupResult(string expected, str var enabledDiagnostics = codeCleanupService.GetAllDiagnostics(); var newDoc = await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, new ProgressTracker(), CancellationToken.None); + document, enabledDiagnostics, new ProgressTracker(), options, CancellationToken.None); var actual = await newDoc.GetTextAsync(); diff --git a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs index c1384e96d1c75..4d20802ff3c66 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs @@ -6,10 +6,13 @@ using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Editor.Implementation.Formatting; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; @@ -32,9 +35,9 @@ private static Dictionary SmartIndentButDoNotFormatWhileTypi { return new Dictionary { - { new OptionKey2(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Smart }, - { new OptionKey2(FormattingBehaviorOptions.AutoFormattingOnTyping, LanguageNames.CSharp), false }, - { new OptionKey2(BraceCompletionOptions.AutoFormattingOnCloseBrace, LanguageNames.CSharp), false }, + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Smart }, + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp), false }, + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, LanguageNames.CSharp), false }, }; } @@ -423,103 +426,8 @@ public void M() var document = workspace.CurrentSolution.Projects.Single().Documents.Single(); var syntaxRoot = await document.GetSyntaxRootAsync(); - - var node = Formatter.Format(syntaxRoot, spans, workspace); - Assert.Equal(expected, node.ToFullString()); - } - - [WorkItem(987373, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/987373")] - [WpfFact, Trait(Traits.Feature, Traits.Features.Formatting)] - public async Task FormatSpansWithCollapsing() - { - var code = @"class C -{ - public void M() - { - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - [|if(true){}|] - while(true){} - [|if(true){}|] - } -}"; - var expected = @"class C -{ - public void M() - { - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - if (true) { } - while (true) { } - if (true) { } - } -}"; - using var workspace = TestWorkspace.CreateCSharp(code); - var subjectDocument = workspace.Documents.Single(); - var spans = subjectDocument.SelectedSpans; - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(FormattingBehaviorOptions.AllowDisjointSpanMerging, true))); - - var document = workspace.CurrentSolution.Projects.Single().Documents.Single(); - var syntaxRoot = await document.GetSyntaxRootAsync(); - - var node = Formatter.Format(syntaxRoot, spans, workspace); + var options = await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None).ConfigureAwait(false); + var node = Formatter.Format(syntaxRoot, spans, workspace.Services, options, rules: null, CancellationToken.None); Assert.Equal(expected, node.ToFullString()); } @@ -1171,7 +1079,7 @@ class C1 }"; var optionSet = new Dictionary { - { new OptionKey2(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None } + { new OptionKey2(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None } }; AssertFormatAfterTypeChar(code, expected, optionSet); } @@ -1202,7 +1110,7 @@ class C var optionSet = new Dictionary { - { new OptionKey2(BraceCompletionOptions.AutoFormattingOnCloseBrace, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, LanguageNames.CSharp), false } }; AssertFormatAfterTypeChar(code, expected, optionSet); @@ -1234,7 +1142,7 @@ class C var optionSet = new Dictionary { - { new OptionKey2(FormattingBehaviorOptions.AutoFormattingOnTyping, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp), false } }; AssertFormatAfterTypeChar(code, expected, optionSet); @@ -1266,7 +1174,7 @@ static void Main() var optionSet = new Dictionary { - { new OptionKey2(FormattingBehaviorOptions.AutoFormattingOnTyping, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp), false } }; AssertFormatAfterTypeChar(code, expected, optionSet); @@ -1324,7 +1232,7 @@ class C var optionSet = new Dictionary { - { new OptionKey2(FormattingBehaviorOptions.AutoFormattingOnSemicolon, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnSemicolon, LanguageNames.CSharp), false } }; AssertFormatAfterTypeChar(code, expected, optionSet); @@ -1356,7 +1264,7 @@ class C var optionSet = new Dictionary { - { new OptionKey2(FormattingBehaviorOptions.AutoFormattingOnTyping, LanguageNames.CSharp), false } + { new OptionKey2(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp), false } }; AssertFormatAfterTypeChar(code, expected, optionSet); @@ -2262,6 +2170,38 @@ public void SeparateGroups_GroupIfSorted_RecognizeSystemNotFirst() AssertFormatWithView(expected, code, (GenerationOptions.SeparateImportDirectiveGroups, true)); } + [WpfFact] + [WorkItem(58157, "https://github.com/dotnet/roslyn/issues/58157")] + [Trait(Traits.Feature, Traits.Features.Formatting)] + public void FormatImplicitObjectCollection() + { + var code = @"class Program +{ + static void Main(string[] args) + { + $$List list = new() + { + 1, 2, 3, 4, + }; + } +} +"; + + var expected = @"class Program +{ + static void Main(string[] args) + { + $$List list = new() + { + 1, 2, 3, 4, + }; + } +} +"; + + AssertFormatWithView(expected, code); + } + [Fact, WorkItem(49492, "https://github.com/dotnet/roslyn/issues/49492")] public void PreserveAnnotationsOnMultiLineTrivia() { @@ -2284,7 +2224,11 @@ class Test var annotatedMarkerTrivia = markerTrivia.WithAdditionalAnnotations(annotation); root = root.ReplaceTrivia(markerTrivia, annotatedMarkerTrivia); - var formattedRoot = Formatter.Format(root, new AdhocWorkspace()); + using var workspace = new AdhocWorkspace(); + + var options = CSharpSyntaxFormattingOptions.Default; + + var formattedRoot = Formatter.Format(root, workspace.Services, options, CancellationToken.None); var annotatedTrivia = formattedRoot.GetAnnotatedTrivia("marker"); Assert.Single(annotatedTrivia); diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs index bbd7278095aa0..ab19697d14108 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/CSharpFormatterTestsBase.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; +using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -81,9 +82,9 @@ private static async Task TokenFormatWorkerAsync(TestWorkspace workspace, ITextB var rules = formattingRuleProvider.CreateRule(document, position).Concat(Formatter.GetDefaultFormattingRules(document)); - var documentOptions = await document.GetOptionsAsync(); - var formatter = new CSharpSmartTokenFormatter(documentOptions, rules, root); - var changes = await formatter.FormatTokenAsync(workspace, token, CancellationToken.None); + var options = await IndentationOptions.FromDocumentAsync(document, CancellationToken.None); + var formatter = new CSharpSmartTokenFormatter(options, rules, root); + var changes = await formatter.FormatTokenAsync(workspace.Services, token, CancellationToken.None); ApplyChanges(buffer, changes); } diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterEnterOnTokenTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterEnterOnTokenTests.cs index 00957a31eb98f..c2479a5ff807f 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterEnterOnTokenTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterEnterOnTokenTests.cs @@ -5,11 +5,13 @@ #nullable disable using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Indentation; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -1515,12 +1517,12 @@ private static async Task AssertIndentUsingSmartTokenFormatterAsync( var root = (await document.GetSyntaxRootAsync()) as CompilationUnitSyntax; - var optionService = workspace.Services.GetRequiredService(); + var options = await IndentationOptions.FromDocumentAsync(document, CancellationToken.None); Assert.True( CSharpIndentationService.ShouldUseSmartTokenFormatterInsteadOfIndenter( - Formatter.GetDefaultFormattingRules(workspace, root.Language), - root, line.AsTextLine(), optionService, await document.GetOptionsAsync(), out _)); + Formatter.GetDefaultFormattingRules(document), + root, line.AsTextLine(), options, out _)); var actualIndentation = await GetSmartTokenFormatterIndentationWorkerAsync(workspace, buffer, indentationLine, ch); Assert.Equal(expectedIndentation.Value, actualIndentation); @@ -1546,7 +1548,7 @@ private static async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndente // create tree service using var workspace = TestWorkspace.CreateCSharp(code); workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp, indentStyle) + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle) .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); var hostdoc = workspace.Documents.First(); var buffer = hostdoc.GetTextBuffer(); @@ -1558,12 +1560,12 @@ private static async Task AssertIndentNotUsingSmartTokenFormatterButUsingIndente var root = (await document.GetSyntaxRootAsync()) as CompilationUnitSyntax; - var optionService = workspace.Services.GetRequiredService(); + var options = await IndentationOptions.FromDocumentAsync(document, CancellationToken.None); Assert.False( CSharpIndentationService.ShouldUseSmartTokenFormatterInsteadOfIndenter( - Formatter.GetDefaultFormattingRules(workspace, root.Language), - root, line.AsTextLine(), optionService, await document.GetOptionsAsync(), out _)); + Formatter.GetDefaultFormattingRules(document), + root, line.AsTextLine(), options, out _)); TestIndentation(workspace, indentationLine, expectedIndentation); } diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs index 92cb204305c25..eaac1999653f6 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs @@ -3013,7 +3013,7 @@ private static void AssertSmartIndentInProjection( using var workspace = TestWorkspace.CreateCSharp(markup, parseOptions: option, composition: s_compositionWithTestFormattingRules); workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp, indentStyle) + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle) .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); var subjectDocument = workspace.Documents.Single(); @@ -3061,7 +3061,7 @@ private static void AssertSmartIndent( using var workspace = TestWorkspace.CreateCSharp(code, parseOptions: option); workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp, indentStyle) + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle) .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); TestIndentation(workspace, indentationLine, expectedIndentation); } @@ -3093,7 +3093,7 @@ private static void AssertSmartIndent( using var workspace = TestWorkspace.CreateCSharp(code, parseOptions: option); workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp, indentStyle) + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle) .WithChangedOption(UseTabs, LanguageNames.CSharp, useTabs))); var wpfTextView = workspace.Documents.First().GetTextView(); var line = wpfTextView.TextBuffer.CurrentSnapshot.GetLineFromPosition(wpfTextView.Caret.Position.BufferPosition).LineNumber; diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs index 4599073a45c36..06aaee0c2cf8d 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartTokenFormatterFormatRangeTests.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; +using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -3551,13 +3552,6 @@ internal static void AutoFormatToken(string markup, string expected, bool useTab Assert.Equal(expected, newSnapshot.GetText()); } - private static Tuple> GetService( - TestWorkspace workspace) - { - var options = workspace.Options; - return Tuple.Create(options, Formatter.GetDefaultFormattingRules(workspace, LanguageNames.CSharp)); - } - private static Task AutoFormatOnColonAsync(string codeWithMarker, string expected, SyntaxKind startTokenKind) => AutoFormatOnMarkerAsync(codeWithMarker, expected, SyntaxKind.ColonToken, startTokenKind); @@ -3580,12 +3574,12 @@ private static async Task AutoFormatOnMarkerAsync(string initialMarkup, string e workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options .WithChangedOption(FormattingOptions2.UseTabs, LanguageNames.CSharp, useTabs))); - var tuple = GetService(workspace); var testDocument = workspace.Documents.Single(); var buffer = testDocument.GetTextBuffer(); var position = testDocument.CursorPosition.Value; var document = workspace.CurrentSolution.GetDocument(testDocument.Id); + var rules = Formatter.GetDefaultFormattingRules(document); var root = (CompilationUnitSyntax)await document.GetSyntaxRootAsync(); var endToken = root.FindToken(position); @@ -3595,7 +3589,8 @@ private static async Task AutoFormatOnMarkerAsync(string initialMarkup, string e } Assert.Equal(tokenKind, endToken.Kind()); - var formatter = new CSharpSmartTokenFormatter(tuple.Item1, tuple.Item2, root); + var options = await IndentationOptions.FromDocumentAsync(document, CancellationToken.None); + var formatter = new CSharpSmartTokenFormatter(options, rules, root); var tokenRange = FormattingRangeHelper.FindAppropriateRange(endToken); if (tokenRange == null) @@ -3610,7 +3605,7 @@ private static async Task AutoFormatOnMarkerAsync(string initialMarkup, string e return; } - var changes = formatter.FormatRange(workspace, tokenRange.Value.Item1, tokenRange.Value.Item2, CancellationToken.None); + var changes = formatter.FormatRange(workspace.Services, tokenRange.Value.Item1, tokenRange.Value.Item2, CancellationToken.None); var actual = GetFormattedText(buffer, changes); Assert.Equal(expected, actual); } diff --git a/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs b/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs index 06c437d0a5d95..68f5385c5b729 100644 --- a/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs +++ b/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs @@ -1618,7 +1618,7 @@ static void Main(string[] args) [WorkItem(54544, "https://github.com/dotnet/roslyn/issues/54544")] public async Task TestAddUsingsEditorBrowsableAdvancedDifferentProjectOptionOff() { - const string InitialWorkspace = @" + var initialWorkspace = @" @@ -1644,8 +1644,8 @@ static void Main(string[] args) "; - await TestMissingAsync(InitialWorkspace, new TestParameters( - options: Option(CompletionOptions.Metadata.HideAdvancedMembers, true))); + await TestMissingAsync(initialWorkspace, new TestParameters( + codeActionOptions: CodeActionOptions.Default with { HideAdvancedMembers = true })); } } } diff --git a/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs b/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs index f8e4adc7628a7..c10e168658969 100644 --- a/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs @@ -1409,5 +1409,51 @@ public B(int x) } }", index: 1); } + + [WorkItem(58593, "https://github.com/dotnet/roslyn/issues/58593")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] + public async Task TestStructWithFieldInitializer() + { + var source = @" +struct [||]{|CS8983:S|} +{ + object X = 1; +} +"; + var fixedSource = @" +struct S +{ + object X = 1; + + public S() + { + } +} +"; + + await new VerifyCodeFix.Test + { + TestCode = source.Replace("[||]", ""), + FixedCode = fixedSource, + LanguageVersion = LanguageVersion.Preview, + }.RunAsync(); + + await TestRefactoringMissingAsync(source); + } + + [WorkItem(58593, "https://github.com/dotnet/roslyn/issues/58593")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] + public async Task TestMissingInStructWithoutFieldInitializer() + { + var source = @" +struct [||]S +{ + object X; +} +"; + + await TestCodeFixMissingAsync(source); + await TestRefactoringMissingAsync(source); + } } } diff --git a/src/EditorFeatures/CSharpTest/GenerateFromMembers/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersTests.cs b/src/EditorFeatures/CSharpTest/GenerateFromMembers/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersTests.cs index d4a65a2d074dd..8bd5bac97f162 100644 --- a/src/EditorFeatures/CSharpTest/GenerateFromMembers/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateFromMembers/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersTests.cs @@ -2,39 +2,59 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddConstructorParametersFromMembers; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; -using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.NamingStyles; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.GenerateFromMembers.AddConstructorParameters { - public class AddConstructorParametersFromMembersTests : AbstractCSharpCodeActionTest + using VerifyCS = Editor.UnitTests.CodeActions.CSharpCodeRefactoringVerifier; + + public class AddConstructorParametersFromMembersTests { - protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) - => new AddConstructorParametersFromMembersCodeRefactoringProvider(); + private const string FieldNamesCamelCaseWithFieldUnderscorePrefixEditorConfig = @" +[*.cs] +dotnet_naming_style.field_camel_case.capitalization = camel_case +dotnet_naming_style.field_camel_case.required_prefix = field_ +dotnet_naming_symbols.fields.applicable_kinds = field +dotnet_naming_symbols.fields.applicable_accessibilities = * +dotnet_naming_rule.fields_should_be_camel_case.severity = error +dotnet_naming_rule.fields_should_be_camel_case.symbols = fields +dotnet_naming_rule.fields_should_be_camel_case.style = field_camel_case +"; - private readonly NamingStylesTestOptionSets options = new NamingStylesTestOptionSets(LanguageNames.CSharp); + private const string FieldNamesCamelCaseWithFieldUnderscorePrefixEndUnderscoreSuffixEditorConfig = + FieldNamesCamelCaseWithFieldUnderscorePrefixEditorConfig + @" +dotnet_naming_style.field_camel_case.required_suffix = _End +"; - protected override ImmutableArray MassageActions(ImmutableArray actions) - => FlattenActions(actions); + private const string ParameterNamesCamelCaseWithPUnderscorePrefixEditorConfig = @" +[*.cs] +dotnet_naming_style.p_camel_case.capitalization = camel_case +dotnet_naming_style.p_camel_case.required_prefix = p_ +dotnet_naming_symbols.parameters.applicable_kinds = parameter +dotnet_naming_symbols.parameters.applicable_accessibilities = * +dotnet_naming_rule.parameters_should_be_camel_case.severity = error +dotnet_naming_rule.parameters_should_be_camel_case.symbols = parameters +dotnet_naming_rule.parameters_should_be_camel_case.style = p_camel_case +"; + + private const string ParameterNamesCamelCaseWithPUnderscorePrefixEndUnderscoreSuffixEditorConfig = + ParameterNamesCamelCaseWithPUnderscorePrefixEditorConfig + @" +dotnet_naming_style.p_camel_case.required_suffix = _End +"; [WorkItem(308077, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/308077")] [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestAdd1() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -47,6 +67,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -59,7 +80,182 @@ public Program(int i, string s) this.i = i; this.s = s; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] + [WorkItem(58040, "https://github.com/dotnet/roslyn/issues/58040")] + public async Task TestProperlyWrapParameters1() + { + await new VerifyCS.Test + { + TestCode = +@"using System.Collections.Generic; + +class Program +{ + [|int i; + string s;|] + + public Program( + int i) + { + this.i = i; + } +}", + FixedCode = +@"using System.Collections.Generic; + +class Program +{ + int i; + string s; + + public Program( + int i, string s) + { + this.i = i; + this.s = s; + } +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] + [WorkItem(58040, "https://github.com/dotnet/roslyn/issues/58040")] + public async Task TestProperlyWrapParameters2() + { + await new VerifyCS.Test + { + TestCode = +@"using System.Collections.Generic; + +class Program +{ + [|int i; + string s; + bool b;|] + + public Program( + int i, + string s) + { + this.i = i; + this.s = s; + } +}", + FixedCode = +@"using System.Collections.Generic; + +class Program +{ + int i; + string s; + bool b; + + public Program( + int i, + string s, + bool b) + { + this.i = i; + this.s = s; + this.b = b; + } +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int, string)"), codeAction.Title) + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] + [WorkItem(58040, "https://github.com/dotnet/roslyn/issues/58040")] + public async Task TestProperlyWrapParameters3() + { + await new VerifyCS.Test + { + TestCode = +@"using System.Collections.Generic; + +class Program +{ + [|int i; + string s; + bool b;|] + + public Program(int i, + string s) + { + this.i = i; + this.s = s; + } +}", + FixedCode = +@"using System.Collections.Generic; + +class Program +{ + int i; + string s; + bool b; + + public Program(int i, + string s, + bool b) + { + this.i = i; + this.s = s; + this.b = b; + } +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int, string)"), codeAction.Title) + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] + [WorkItem(58040, "https://github.com/dotnet/roslyn/issues/58040")] + public async Task TestProperlyWrapParameters4() + { + await new VerifyCS.Test + { + TestCode = +@"using System.Collections.Generic; + +class Program +{ + [|int i; + string s; + bool b;|] + + public Program(int i, + string s) + { + this.i = i; + this.s = s; + } +}", + FixedCode = +@"using System.Collections.Generic; + +class Program +{ + int i; + string s; + bool b; + + public Program(int i, + string s, + bool b) + { + this.i = i; + this.s = s; + this.b = b; + } +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int, string)"), codeAction.Title) + }.RunAsync(); } [WorkItem(308077, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/308077")] @@ -67,7 +263,9 @@ public Program(int i, string s) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestAddOptional1() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test() + { + TestCode = @"using System.Collections.Generic; class Program @@ -80,6 +278,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -92,7 +291,10 @@ public Program(int i, string s = null) this.i = i; this.s = s; } -}", index: 1, title: string.Format(FeaturesResources.Add_optional_parameters_to_0, "Program(int)")); +}", + CodeActionIndex = 1, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_optional_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(308077, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/308077")] @@ -101,7 +303,9 @@ public Program(int i, string s = null) public async Task TestAddToConstructorWithMostMatchingParameters1() { // behavior change with 33603, now all constructors offered - await TestInRegularAndScriptAsync( + await new VerifyCS.Test() + { + TestCode = @"using System.Collections.Generic; class Program @@ -120,6 +324,7 @@ public Program(int i, string s) : this(i) this.s = s; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -138,7 +343,10 @@ public Program(int i, string s, bool b) : this(i) this.s = s; this.b = b; } -}", index: 1, title: string.Format(FeaturesResources.Add_to_0, "Program(int, string)")); +}", + CodeActionIndex = 1, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "Program(int, string)"), codeAction.Title) + }.RunAsync(); } [WorkItem(308077, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/308077")] @@ -147,7 +355,9 @@ public Program(int i, string s, bool b) : this(i) public async Task TestAddOptionalToConstructorWithMostMatchingParameters1() { // Behavior change with #33603, now all constructors are offered - await TestInRegularAndScriptAsync( + await new VerifyCS.Test() + { + TestCode = @"using System.Collections.Generic; class Program @@ -166,6 +376,7 @@ public Program(int i, string s) : this(i) this.s = s; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -184,13 +395,18 @@ public Program(int i, string s, bool b = false) : this(i) this.s = s; this.b = b; } -}", index: 3, title: string.Format(FeaturesResources.Add_to_0, "Program(int, string)")); +}", + CodeActionIndex = 3, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "Program(int, string)"), codeAction.Title) + }.RunAsync(); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestSmartTagDisplayText1() { - await TestSmartTagTextAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -203,13 +419,16 @@ public Program(bool b) this.b = b; } }", -string.Format(FeaturesResources.Add_parameters_to_0, "Program(bool)")); + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(bool)"), codeAction.Title) + }.RunAsync(); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestSmartTagDisplayText2() { - await TestSmartTagTextAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -222,14 +441,15 @@ public Program(bool b) this.b = b; } }", -string.Format(FeaturesResources.Add_optional_parameters_to_0, "Program(bool)"), -index: 1); + CodeActionIndex = 1, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_optional_parameters_to_0, "Program(bool)"), codeAction.Title) + }.RunAsync(); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTuple() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @"class Program { [|(int, string) i; @@ -256,7 +476,7 @@ public Program((int, string) i, (string, int) s) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleWithNames() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @"class Program { [|(int a, string b) i; @@ -283,7 +503,7 @@ public Program((int a, string b) i, (string c, int d) s) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleWithDifferentNames() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @"class Program { [|(int a, string b) i; @@ -310,7 +530,9 @@ public Program((int e, string f) i, (string c, int d) s) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleOptionalCSharp7() { - await TestAsync( + await new VerifyCS.Test + { + TestCode = @"class Program { [|(int, string) i; @@ -321,6 +543,7 @@ public Program((int, string) i) this.i = i; } }", + FixedCode = @"class Program { (int, string) i; @@ -332,13 +555,17 @@ public Program((int, string) i) this.s = s; } }", -index: 1, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7)); + CodeActionIndex = 1, + LanguageVersion = LanguageVersion.CSharp7 + }.RunAsync(); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleOptional() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"class Program { [|(int, string) i; @@ -349,6 +576,7 @@ public Program((int, string) i) this.i = i; } }", + FixedCode = @"class Program { (int, string) i; @@ -360,13 +588,16 @@ public Program((int, string) i, (string, int) s = default) this.s = s; } }", -index: 1); + CodeActionIndex = 1 + }.RunAsync(); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleOptionalWithNames_CSharp7() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"class Program { [|(int a, string b) i; @@ -377,6 +608,7 @@ public Program((int a, string b) i) this.i = i; } }", + FixedCode = @"class Program { (int a, string b) i; @@ -388,14 +620,17 @@ public Program((int a, string b) i) this.s = s; } }", -parseOptions: TestOptions.Regular7, -index: 1); + LanguageVersion = LanguageVersion.CSharp7, + CodeActionIndex = 1 + }.RunAsync(); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleOptionalWithNamesCSharp7() { - await TestAsync( + await new VerifyCS.Test + { + TestCode = @"class Program { [|(int a, string b) i; @@ -406,6 +641,7 @@ public Program((int a, string b) i) this.i = i; } }", + FixedCode = @"class Program { (int a, string b) i; @@ -417,13 +653,17 @@ public Program((int a, string b) i) this.s = s; } }", -index: 1, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7)); + CodeActionIndex = 1, + LanguageVersion = LanguageVersion.CSharp7 + }.RunAsync(); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleOptionalWithNames() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"class Program { [|(int a, string b) i; @@ -434,6 +674,7 @@ public Program((int a, string b) i) this.i = i; } }", + FixedCode = @"class Program { (int a, string b) i; @@ -445,13 +686,16 @@ public Program((int a, string b) i, (string c, int d) s = default) this.s = s; } }", -index: 1); + CodeActionIndex = 1 + }.RunAsync(); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleOptionalWithDifferentNames() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"class Program { [|(int a, string b) i; @@ -462,6 +706,7 @@ public Program((int e, string f) i) this.i = i; } }", + FixedCode = @"class Program { [|(int a, string b) i; @@ -472,13 +717,15 @@ public Program((int e, string f) i, (string c, int d) s = default) this.i = i; this.s = s; } -}", index: 1); +}", + CodeActionIndex = 1 + }.RunAsync(); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleWithNullable() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @"class Program { [|(int?, bool?) i; @@ -505,8 +752,10 @@ public Program((int?, bool?) i, (byte?, long?) s) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestTupleWithGenericss() { - await TestInRegularAndScriptAsync( -@"class Program + await VerifyCS.VerifyRefactoringAsync( +@"using System.Collections.Generic; + +class Program { [|(List, List) i; (List, List) s;|] @@ -516,7 +765,9 @@ public Program((List, List) i) this.i = i; } }", -@"class Program +@"using System.Collections.Generic; + +class Program { (List, List) i; (List, List) s; @@ -533,8 +784,9 @@ public Program((List, List) i, (List, List) s) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestAddParamtersToConstructorBySelectOneMember() { - await TestInRegularAndScriptAsync( -@" + await VerifyCS.VerifyRefactoringAsync( +@"using System.Collections.Generic; + class C { int i; @@ -547,7 +799,8 @@ public C(int i, int j) this.j = j; } }", -@" +@"using System.Collections.Generic; + class C { int i; @@ -567,7 +820,7 @@ public C(int i, int j, (List, List) s) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestParametersAreStillRightIfMembersAreOutOfOrder() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @" class C { @@ -601,7 +854,7 @@ public C(int i, int j, int k) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestMissingIfFieldsAlreadyExistingInConstructor() { - await TestMissingAsync( + var source = @" class C { @@ -610,15 +863,15 @@ class C public C(string barBar, int fooFoo) { } -}" - ); +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); } [WorkItem(28775, "https://github.com/dotnet/roslyn/issues/28775")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestMissingIfPropertyAlreadyExistingInConstructor() { - await TestMissingAsync( + var source = @" class C { @@ -627,16 +880,15 @@ class C public C(string bar, int helloWorld) { } -}" - ); - +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); } [WorkItem(28775, "https://github.com/dotnet/roslyn/issues/28775")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNormalProperty() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @" class C { @@ -663,7 +915,7 @@ public C(int i, int hello) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestConstructorWithNoParameters() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @" class C { @@ -691,20 +943,21 @@ public C(int i, int hello) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestDefaultConstructor() { - await TestMissingAsync( + var source = @" class C { [|int i;|] int Hello { get; set; } -}"); +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); } [WorkItem(33601, "https://github.com/dotnet/roslyn/issues/33601")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestPartialSelected() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @" class C { @@ -731,7 +984,7 @@ public C(int i, int j) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestPartialMultipleSelected() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @" class C { @@ -761,7 +1014,7 @@ public C(int i, int j, int k) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestPartialMultipleSelected2() { - await TestInRegularAndScriptAsync( + await VerifyCS.VerifyRefactoringAsync( @" class C { @@ -790,7 +1043,9 @@ public C(int i, int j) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestMultipleConstructors_FirstofThree() { - var source = + await new VerifyCS.Test + { + TestCode = @" class C { @@ -804,8 +1059,8 @@ public C(int i, int j) public C(int i, int j, int k) { } -}"; - var expected = +}", + FixedCode = @" class C { @@ -814,14 +1069,15 @@ public C(int i, int l) { this.l = l; } - public C(int i, int j) + public {|CS0111:C|}(int i, int j) { } public C(int i, int j, int k) { } -}"; - await TestInRegularAndScriptAsync(source, expected, index: 0, title: string.Format(FeaturesResources.Add_to_0, "C(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] @@ -855,11 +1111,17 @@ public C(int i, int j, int l) { this.l = l; } - public C(int i, int j, int k) + public {|CS0111:C|}(int i, int j, int k) { } }"; - await TestInRegularAndScriptAsync(source, expected, index: 1, title: string.Format(FeaturesResources.Add_to_0, "C(int, int)")); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + CodeActionIndex = 1, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int, int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] @@ -898,7 +1160,13 @@ public C(int i, int j, int k, int l) this.l = l; } }"; - await TestInRegularAndScriptAsync(source, expected, index: 2, title: string.Format(FeaturesResources.Add_to_0, "C(int, int, int)")); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + CodeActionIndex = 2, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int, int, int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] @@ -929,14 +1197,20 @@ public C(int i, int l = 0) { this.l = l; } - public C(int i, int j) + public {|CS0111:C|}(int i, int j) { } public C(int i, int j, int k) { } }"; - await TestInRegularAndScriptAsync(source, expected, index: 3, title: string.Format(FeaturesResources.Add_to_0, "C(int)")); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + CodeActionIndex = 3, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] @@ -970,11 +1244,18 @@ public C(int i, int j, int l = 0) { this.l = l; } - public C(int i, int j, int k) + public {|CS0111:C|}(int i, int j, int k) { } }"; - await TestInRegularAndScriptAsync(source, expected, index: 4, title: string.Format(FeaturesResources.Add_to_0, "C(int, int)")); + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + CodeActionIndex = 4, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int, int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] @@ -1012,7 +1293,13 @@ public C(int i, int j, int k, int l = 0) this.l = l; } }"; - await TestInRegularAndScriptAsync(source, expected, index: 5, title: string.Format(FeaturesResources.Add_to_0, "C(int, int, int)")); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + CodeActionIndex = 5, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int, int, int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] @@ -1066,7 +1353,13 @@ public C(int i, double j, int k, int l) this.l = l; } }"; - await TestInRegularAndScriptAsync(source, expected, index: 1, title: string.Format(FeaturesResources.Add_to_0, "C(int, double, int)")); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + CodeActionIndex = 1, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int, double, int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] @@ -1112,19 +1405,27 @@ public C(int i, double j = 0, int l = 0) } // index 1, and 4 as optional - public C(int i, double j, int k) + public {|CS0111:C|}(int i, double j, int k) { } }"; - await TestInRegularAndScriptAsync(source, expected, index: 3, title: string.Format(FeaturesResources.Add_to_0, "C(int, double)")); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + CodeActionIndex = 3, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int, double)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestMultipleConstructors_AllMustBeOptional() { - var source = -@" + await new VerifyCS.Test + { + TestCode = + @" class C { int [|p|]; @@ -1137,8 +1438,8 @@ public C(double j, int k = 0) public C(int l, double m, int n = 0) { } -}"; - var expected = +}", + FixedCode = @" class C { @@ -1153,8 +1454,9 @@ public C(double j, int k = 0) public C(int l, double m, int n = 0) { } -}"; - await TestInRegularAndScriptAsync(source, expected, index: 0, title: string.Format(FeaturesResources.Add_to_0, "C(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33603, "https://github.com/dotnet/roslyn/issues/33603")] @@ -1192,19 +1494,25 @@ public C(int l, double m, int n = 0, int p = 0) this.p = p; } }"; - await TestInRegularAndScriptAsync(source, expected, index: 2, title: string.Format(FeaturesResources.Add_to_0, "C(int, double, int)")); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + CodeActionIndex = 2, + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_to_0, "C(int, double, int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(33623, "https://github.com/dotnet/roslyn/issues/33623")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestDeserializationConstructor() { - await TestMissingAsync( + var source = @" using System; using System.Runtime.Serialization; -class C : ISerializable +class C : {|CS0535:ISerializable|} { int [|i|]; @@ -1212,7 +1520,8 @@ private C(SerializationInfo info, StreamingContext context) { } } -"); +"; + await VerifyCS.VerifyRefactoringAsync(source, source); } [WorkItem(35775, "https://github.com/dotnet/roslyn/issues/35775")] @@ -1241,7 +1550,12 @@ public C(int p_v_End) } } "; - await TestInRegularAndScriptAsync(source, expected, index: 0, options: options.ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffix); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + EditorConfig = ParameterNamesCamelCaseWithPUnderscorePrefixEndUnderscoreSuffixEditorConfig + }.RunAsync(); } [WorkItem(35775, "https://github.com/dotnet/roslyn/issues/35775")] @@ -1270,7 +1584,12 @@ public C(int p_v) } } "; - await TestInRegularAndScriptAsync(source, expected, index: 0, options: options.ParameterNamesAreCamelCaseWithPUnderscorePrefix); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + EditorConfig = ParameterNamesCamelCaseWithPUnderscorePrefixEditorConfig + }.RunAsync(); } [WorkItem(35775, "https://github.com/dotnet/roslyn/issues/35775")] @@ -1299,8 +1618,12 @@ public C(int p_v) } } "; - await TestInRegularAndScriptAsync(source, expected, index: 0, options: options.MergeStyles( - options.FieldNamesAreCamelCaseWithFieldUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefix)); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + EditorConfig = FieldNamesCamelCaseWithFieldUnderscorePrefixEditorConfig + ParameterNamesCamelCaseWithPUnderscorePrefixEditorConfig + }.RunAsync(); } [WorkItem(35775, "https://github.com/dotnet/roslyn/issues/35775")] @@ -1329,8 +1652,13 @@ public C(int p_v) } } "; - await TestInRegularAndScriptAsync(source, expected, index: 0, options: options.MergeStyles( - options.FieldNamesAreCamelCaseWithFieldUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefix)); + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + EditorConfig = FieldNamesCamelCaseWithFieldUnderscorePrefixEditorConfig + ParameterNamesCamelCaseWithPUnderscorePrefixEditorConfig + }.RunAsync(); } [WorkItem(35775, "https://github.com/dotnet/roslyn/issues/35775")] @@ -1359,8 +1687,12 @@ public C(int p_v) } } "; - await TestInRegularAndScriptAsync(source, expected, index: 0, options: options.MergeStyles( - options.FieldNamesAreCamelCaseWithFieldUnderscorePrefix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefix)); + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + EditorConfig = FieldNamesCamelCaseWithFieldUnderscorePrefixEditorConfig + ParameterNamesCamelCaseWithPUnderscorePrefixEditorConfig + }.RunAsync(); } [WorkItem(35775, "https://github.com/dotnet/roslyn/issues/35775")] @@ -1377,7 +1709,13 @@ public C() } } "; - await TestMissingAsync(source, parameters: new TestParameters(options: options.FieldNamesAreCamelCaseWithFieldUnderscorePrefixAndUnderscoreEndSuffix)); + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = source, + EditorConfig = FieldNamesCamelCaseWithFieldUnderscorePrefixEndUnderscoreSuffixEditorConfig + }.RunAsync(); } [WorkItem(35775, "https://github.com/dotnet/roslyn/issues/35775")] @@ -1408,8 +1746,13 @@ public C(int p_test) } } "; - await TestInRegularAndScriptAsync(source, expected, index: 0, options: options.MergeStyles( - options.FieldNamesAreCamelCaseWithFieldUnderscorePrefixAndUnderscoreEndSuffix, options.ParameterNamesAreCamelCaseWithPUnderscorePrefix)); + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + EditorConfig = FieldNamesCamelCaseWithFieldUnderscorePrefixEndUnderscoreSuffixEditorConfig + ParameterNamesCamelCaseWithPUnderscorePrefixEditorConfig + }.RunAsync(); } [WorkItem(35775, "https://github.com/dotnet/roslyn/issues/35775")] @@ -1438,14 +1781,22 @@ public C(int p_test) } } "; - await TestInRegularAndScriptAsync(source, expected, index: 0, options: options.ParameterNamesAreCamelCaseWithPUnderscorePrefix); + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = expected, + EditorConfig = ParameterNamesCamelCaseWithPUnderscorePrefixEditorConfig + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelection1() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1458,6 +1809,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1470,14 +1822,18 @@ public Program(int i, string s) this.i = i; this.s = s; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelection2() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1490,6 +1846,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1502,14 +1859,18 @@ public Program(int i, string s) this.i = i; this.s = s; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelection3() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1522,6 +1883,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1534,14 +1896,18 @@ public Program(int i, string s) this.i = i; this.s = s; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelection4() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1554,6 +1920,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1566,14 +1933,18 @@ public Program(int i, string s) this.i = i; this.s = s; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelection5() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1586,6 +1957,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1598,14 +1970,18 @@ public Program(int i, string s) this.i = i; this.s = s; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelection6() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1618,6 +1994,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1630,14 +2007,18 @@ public Program(int i, string s) this.i = i; this.s = s; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMultiVar1() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1650,6 +2031,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1663,14 +2045,18 @@ public Program(int i, string s, string t) this.s = s; this.t = t; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMultiVar2() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1683,6 +2069,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1696,14 +2083,18 @@ public Program(int i, string s, string t) this.s = s; this.t = t; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMultiVar3() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1716,6 +2107,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1728,14 +2120,18 @@ public Program(int i, string s) this.i = i; this.s = s; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMultiVar4() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1748,6 +2144,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1760,14 +2157,18 @@ public Program(int i, string s) this.i = i; this.s = s; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMultiVar5() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1780,6 +2181,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1792,14 +2194,18 @@ public Program(int i, string t) this.i = i; this.t = t; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMultiVar6() { - await TestInRegularAndScriptAsync( + await new VerifyCS.Test + { + TestCode = @"using System.Collections.Generic; class Program @@ -1812,6 +2218,7 @@ public Program(int i) this.i = i; } }", + FixedCode = @"using System.Collections.Generic; class Program @@ -1824,14 +2231,16 @@ public Program(int i, string t) this.i = i; this.t = t; } -}", title: string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)")); +}", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(string.Format(FeaturesResources.Add_parameters_to_0, "Program(int)"), codeAction.Title) + }.RunAsync(); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMissing1() { - await TestMissingInRegularAndScriptAsync( + var source = @"using System.Collections.Generic; class Program @@ -1844,14 +2253,15 @@ public Program(int i) { this.i = i; } -}"); +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMissing2() { - await TestMissingInRegularAndScriptAsync( + var source = @"using System.Collections.Generic; class Program @@ -1863,14 +2273,15 @@ public Program(int i) { this.i = i; } -}"); +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMissing3() { - await TestMissingInRegularAndScriptAsync( + var source = @"using System.Collections.Generic; class Program @@ -1882,14 +2293,15 @@ public Program(int i) { this.i = i; } -}"); +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); } [WorkItem(23271, "https://github.com/dotnet/roslyn/issues/23271")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] public async Task TestNonSelectionMissing4() { - await TestMissingInRegularAndScriptAsync( + var source = @"using System.Collections.Generic; class Program @@ -1901,7 +2313,156 @@ public Program(int i) { this.i = i; } -}"); +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); + } + + [WorkItem(59292, "https://github.com/dotnet/roslyn/issues/59292")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] + public async Task TestPartialClass1() + { + await new VerifyCS.Test + { + TestState = + { + Sources = + { +@" +partial class C +{ + private int [|_v|]; +}", +@" +partial class C +{ + public C() + { + } +}" + } + }, + FixedState = + { + Sources = + { +@" +partial class C +{ + private int _v; +}", +@" +partial class C +{ + public C(int v) + { + _v = v; + } +}" + } + } + }.RunAsync(); + } + + [WorkItem(59292, "https://github.com/dotnet/roslyn/issues/59292")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] + public async Task TestPartialClass2() + { + await new VerifyCS.Test + { + TestState = + { + Sources = + { +@" +partial class C +{ + private int [|_v|]; + + public C() + { + } +}", +@" +partial class C +{ + public C(object goo) + { + } +}" + } + }, + FixedState = + { + Sources = + { +@" +partial class C +{ + private int _v; + + public C() + { + } +}", +@" +partial class C +{ + public C(object goo, int v) + { + _v = v; + } +}" + } + }, + CodeActionIndex = 1 + }.RunAsync(); + } + + [WorkItem(59292, "https://github.com/dotnet/roslyn/issues/59292")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddConstructorParametersFromMembers)] + public async Task TestPartialClass3() + { + await new VerifyCS.Test + { + TestState = + { + Sources = + { +@" +partial class C +{ + private int [|_v|]; +}", +@" +partial class C +{ + public C() + { + } +}" + } + }, + FixedState = + { + Sources = + { +@" +partial class C +{ + private int _v; +}", +@" +partial class C +{ + public C(int v = 0) + { + _v = v; + } +}" + } + }, + CodeActionIndex = 1 + }.RunAsync(); } } } diff --git a/src/EditorFeatures/CSharpTest/GenerateFromMembers/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs b/src/EditorFeatures/CSharpTest/GenerateFromMembers/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs index bcb254453e86a..5c48b85324502 100644 --- a/src/EditorFeatures/CSharpTest/GenerateFromMembers/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateFromMembers/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersTests.cs @@ -93,7 +93,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && a == program.a; } }"; @@ -107,6 +107,39 @@ public override bool Equals(object obj) }.RunAsync(); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)] + public async Task TestEqualsSingleField_CSharp7() + { + var code = +@"using System.Collections.Generic; + +class Program +{ + [|int a;|] +}"; + var fixedCode = +@"using System.Collections.Generic; + +class Program +{ + int a; + + public override bool Equals(object obj) + { + return obj is Program program && + a == program.a; + } +}"; + + await new VerifyCS.Test + { + TestCode = code, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp7, + Options = { PreferImplicitTypeWithInfo() }, + }.RunAsync(); + } + [WorkItem(39916, "https://github.com/dotnet/roslyn/issues/39916")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)] public async Task TestEqualsSingleField_PreferExplicitType() @@ -128,7 +161,7 @@ class Program public override bool Equals(object obj) { Program program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && a == program.a; } }"; @@ -170,7 +203,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && EqualityComparer.Default.Equals(a, program.a); } }"; @@ -260,7 +293,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && a.Equals(program.a); } }"; @@ -294,7 +327,7 @@ class ReallyLongName public override bool Equals(object obj) { var name = obj as ReallyLongName; - return name != null && + return !ReferenceEquals(name, null) && a == name.a; } }"; @@ -328,7 +361,7 @@ class ReallyLongLong public override bool Equals(object obj) { var @long = obj as ReallyLongLong; - return @long != null && + return !ReferenceEquals(@long, null) && a == @long.a; } }"; @@ -366,7 +399,7 @@ class ReallyLongName public override bool Equals(object obj) { var name = obj as ReallyLongName; - return name != null && + return !ReferenceEquals(name, null) && a == name.a && B == name.B; } @@ -405,7 +438,7 @@ class Program : Base public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && i == program.i; } }"; @@ -459,7 +492,7 @@ class Program : Base public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && base.Equals(obj) && i == program.i && S == program.S; @@ -524,7 +557,7 @@ class Program : Middle public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && base.Equals(obj) && i == program.i && S == program.S; @@ -767,7 +800,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && i == program.i; } } @@ -826,7 +859,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && i == program.i; } @@ -866,7 +899,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && j == program.j; } @@ -914,7 +947,7 @@ class Program : Base public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && j == program.j; } @@ -966,7 +999,7 @@ class Program : Base public override bool Equals(object obj) { var program = obj as Program; - return program != null; + return !ReferenceEquals(program, null); } public override int GetHashCode() @@ -1006,7 +1039,7 @@ class Program public override bool Equals(object obj) { Program program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && i == program.i; } @@ -1046,7 +1079,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && EqualityComparer.Default.Equals(i, program.i); } @@ -1086,7 +1119,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && EqualityComparer>.Default.Equals(i, program.i); } @@ -1130,7 +1163,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && i == program.i && S == program.S; } @@ -1331,7 +1364,7 @@ class C public override bool Equals(object obj) { var c = obj as C; - return c != null && + return !ReferenceEquals(c, null) && a.Equals(c.a); } }"; @@ -1366,7 +1399,7 @@ class C public override bool Equals(object obj) { var c = obj as C; - return c != null && + return !ReferenceEquals(c, null) && a.Equals(c.a); } }"; @@ -1400,7 +1433,7 @@ class C public override bool Equals(object obj) { var c = obj as C; - return c != null && + return !ReferenceEquals(c, null) && a.Equals(c.a); } }"; @@ -1434,7 +1467,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && i.Equals(program.i); } @@ -1474,7 +1507,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && i.Equals(program.i); } @@ -1518,7 +1551,7 @@ class Foo public override bool Equals(object obj) { var foo = obj as Foo; - return foo != null && + return !ReferenceEquals(foo, null) && EqualityComparer.Default.Equals(bar, foo.bar); } @@ -1567,7 +1600,7 @@ class Foo public override bool Equals(object obj) { var foo = obj as Foo; - return foo != null && + return !ReferenceEquals(foo, null) && EqualityComparer.Default.Equals(bar, foo.bar); } @@ -1616,7 +1649,7 @@ class Foo public override bool Equals(object obj) { var foo = obj as Foo; - return foo != null && + return !ReferenceEquals(foo, null) && EqualityComparer.Default.Equals(bar, foo.bar); } @@ -1660,7 +1693,7 @@ class Foo where TBar : struct public override bool Equals(object obj) { var foo = obj as Foo; - return foo != null && + return !ReferenceEquals(foo, null) && EqualityComparer.Default.Equals(bar, foo.bar); } @@ -1700,7 +1733,7 @@ class Foo where TBar : struct public override bool Equals(object obj) { var foo = obj as Foo; - return foo != null && + return !ReferenceEquals(foo, null) && EqualityComparer.Default.Equals(bar, foo.bar); } @@ -1744,7 +1777,7 @@ class Foo public override bool Equals(object obj) { var foo = obj as Foo; - return foo != null && + return !ReferenceEquals(foo, null) && bar == foo.bar; } @@ -1788,7 +1821,7 @@ class Foo public override bool Equals(object obj) { var foo = obj as Foo; - return foo != null && + return !ReferenceEquals(foo, null) && bar == foo.bar; } @@ -1831,7 +1864,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && a == program.a && b == program.b; } @@ -1872,7 +1905,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && c == program.c && b == program.b; } @@ -1913,7 +1946,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null; + return !ReferenceEquals(program, null); } }"; @@ -1947,7 +1980,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && F == program.F; } }"; @@ -2103,7 +2136,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && s == program.s; } @@ -2152,7 +2185,7 @@ class Program public override bool Equals(object obj) { Program program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && s == program.s; } @@ -2199,7 +2232,7 @@ class Program public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && s == program.s; } @@ -2304,7 +2337,7 @@ class Foo public override bool Equals(object obj) { var foo = obj as Foo; - return foo != null && + return !ReferenceEquals(foo, null) && BooleanValue == foo.BooleanValue && DecimalValue == foo.DecimalValue && EnumValue == foo.EnumValue && @@ -2367,7 +2400,7 @@ class Foo public override bool Equals(object obj) { var foo = obj as Foo; - return foo != null && + return !ReferenceEquals(foo, null) && Value.Equals(foo.Value) && EqualityComparer.Default.Equals(NullableValue, foo.NullableValue); } @@ -2597,7 +2630,7 @@ public bool Equals(Foo other) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)] - public async Task TestImplementIEquatableOnClass() + public async Task TestImplementIEquatableOnClass_CSharp6() { var code = @" @@ -2624,7 +2657,7 @@ public override bool Equals(object obj) public bool Equals(Program other) { - return other != null && + return !ReferenceEquals(other, null) && s == other.s; } }"; @@ -2640,6 +2673,138 @@ public bool Equals(Program other) }.RunAsync(); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)] + public async Task TestImplementIEquatableOnClass_CSharp7() + { + var code = +@" +using System.Collections.Generic; + +class Program +{ + public string s; + [||] +}"; + var fixedCode = +@" +using System; +using System.Collections.Generic; + +class Program : IEquatable +{ + public string s; + + public override bool Equals(object obj) + { + return Equals(obj as Program); + } + + public bool Equals(Program other) + { + return !(other is null) && + s == other.s; + } +}"; + + await new TestWithDialog + { + TestCode = code, + FixedCode = fixedCode, + MemberNames = default, + OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId), + LanguageVersion = LanguageVersion.CSharp7, + Options = { PreferImplicitTypeWithInfo() }, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)] + public async Task TestImplementIEquatableOnClass_CSharp8() + { + var code = +@" +using System.Collections.Generic; + +class Program +{ + public string s; + [||] +}"; + var fixedCode = +@" +using System; +using System.Collections.Generic; + +class Program : IEquatable +{ + public string s; + + public override bool Equals(object obj) + { + return Equals(obj as Program); + } + + public bool Equals(Program other) + { + return !(other is null) && + s == other.s; + } +}"; + + await new TestWithDialog + { + TestCode = code, + FixedCode = fixedCode, + MemberNames = default, + OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId), + LanguageVersion = LanguageVersion.CSharp8, + Options = { PreferImplicitTypeWithInfo() }, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)] + public async Task TestImplementIEquatableOnClass_CSharp9() + { + var code = +@" +using System.Collections.Generic; + +class Program +{ + public string s; + [||] +}"; + var fixedCode = +@" +using System; +using System.Collections.Generic; + +class Program : IEquatable +{ + public string s; + + public override bool Equals(object obj) + { + return Equals(obj as Program); + } + + public bool Equals(Program other) + { + return other is not null && + s == other.s; + } +}"; + + await new TestWithDialog + { + TestCode = code, + FixedCode = fixedCode, + MemberNames = default, + OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId), + LanguageVersion = LanguageVersion.CSharp9, + Options = { PreferImplicitTypeWithInfo() }, + }.RunAsync(); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)] public async Task TestImplementIEquatableOnClassInNullableContextWithUnannotatedMetadata() { @@ -2667,7 +2832,7 @@ public override bool Equals(object? obj) public bool Equals(Foo? other) { - return other != null && + return !(other is null) && Bar == other.Bar; } }"; @@ -2716,7 +2881,7 @@ public override bool Equals(object? obj) public bool Equals(Foo? other) { - return other != null && + return !(other is null) && Bar == other.Bar; } } @@ -2755,7 +2920,7 @@ class Program : {|CS0535:System.IEquatable|} public override bool Equals(object obj) { var program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && s == program.s; } }"; @@ -2813,7 +2978,7 @@ public void F() public override System.Boolean Equals(System.Object obj) { Class1 @class = obj as Class1; - return @class != null && + return !ReferenceEquals(@class, null) && i == @class.i; } @@ -2847,8 +3012,10 @@ public override System.Int32 GetHashCode() DiagnosticResult.CompilerError("CS0518").WithSpan(7, 9, 7, 15).WithArguments("System.Object"), // /0/Test0.cs(7,32): error CS0518: Predefined type 'System.Object' is not defined or imported DiagnosticResult.CompilerError("CS0518").WithSpan(7, 32, 7, 38).WithArguments("System.Object"), - // /0/Test0.cs(8,16): error CS0518: Predefined type 'System.Object' is not defined or imported - DiagnosticResult.CompilerError("CS0518").WithSpan(8, 16, 8, 30).WithArguments("System.Object"), + // /0/Test0.cs(8,17): error CS0103: The name 'ReferenceEquals' does not exist in the current context + DiagnosticResult.CompilerError("CS0103").WithSpan(8, 17, 8, 32).WithArguments("ReferenceEquals"), + // /0/Test0.cs(8,17): error CS0518: Predefined type 'System.Object' is not defined or imported + DiagnosticResult.CompilerError("CS0518").WithSpan(8, 17, 8, 32).WithArguments("System.Object"), // /0/Test0.cs(9,16): error CS0518: Predefined type 'System.Boolean' is not defined or imported DiagnosticResult.CompilerError("CS0518").WithSpan(9, 16, 9, 29).WithArguments("System.Boolean"), // /0/Test0.cs(12,12): error CS0518: Predefined type 'System.Void' is not defined or imported @@ -2899,7 +3066,7 @@ class Program public override bool Equals(object obj) { Program program = obj as Program; - return program != null && + return !ReferenceEquals(program, null) && i == program.i && S == program.S; } diff --git a/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs b/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs index 3db5264978e21..e98f9c7673c09 100644 --- a/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs @@ -220,5 +220,35 @@ static class [||]C }"); } + + [WorkItem(53012, "https://github.com/dotnet/roslyn/issues/53012")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + public async Task TestNullableTypeParameter() + { + await TestWithPickMembersDialogAsync( +@"class C +{ + public virtual void M(T1? a, T2 b, T1? c, T3? d) {} +} + +class D : C +{ + [||] +}", +@"class C +{ + public virtual void M(T1? a, T2 b, T1? c, T3? d) {} +} + +class D : C +{ + public override void M(T1? a, T2 b, T1? c, T3? d) + where T1 : default + where T3 : default + { + base.M(a, b, c, d); + } +}", new[] { "M" }); + } } } diff --git a/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs b/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs index 5bcd6dca784d2..2022170660e07 100644 --- a/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs +++ b/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs @@ -2040,5 +2040,32 @@ class D : B<{passToBase}>{constraint} }} }}"); } + + [WorkItem(53012, "https://github.com/dotnet/roslyn/issues/53012")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] + public async Task TestNullableGenericType() + { + await TestAllOptionsOffAsync( +@"abstract class C +{ + public abstract void M(T1? a, T2 b, T1? c, T3? d); +} +class [|D|] : C +{ +}", +@"abstract class C +{ + public abstract void M(T1? a, T2 b, T1? c, T3? d); +} +class D : C +{ + public override void M(T1? a, T2 b, T1? c, T3? d) + where T1 : default + where T3 : default + { + throw new System.NotImplementedException(); + } +}"); + } } } diff --git a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementExplicitlyTests.cs b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementExplicitlyTests.cs index 511f26564b02e..03428526a0cab 100644 --- a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementExplicitlyTests.cs +++ b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementExplicitlyTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -11,6 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.ImplementInterface; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ImplementInterface @@ -562,5 +561,160 @@ int IBar.M(int i) } }", index: SingleMember); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [WorkItem(52020, "https://github.com/dotnet/roslyn/issues/52020")] + public async Task TestWithContraints() + { + await TestInRegularAndScriptAsync( +@" +interface IRepro +{ + void A(int value) where T : class; +} + +class Repro : IRepro +{ + public void [||]A(int value) where T : class + { + } +}", +@" +interface IRepro +{ + void A(int value) where T : class; +} + +class Repro : IRepro +{ + void IRepro.A(int value) + { + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [WorkItem(52020, "https://github.com/dotnet/roslyn/issues/52020")] + public async Task TestWithDefaultParameterValues() + { + await TestInRegularAndScriptAsync( +@" +interface IRepro +{ + void A(int value = 0); +} + +class Repro : IRepro +{ + public void [||]A(int value = 0) + { + } +}", +@" +interface IRepro +{ + void A(int value = 0); +} + +class Repro : IRepro +{ + void IRepro.A(int value) + { + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [WorkItem(52020, "https://github.com/dotnet/roslyn/issues/52020")] + public async Task TestWithMismatchedDefaultParameterValues() + { + await TestInRegularAndScriptAsync( +@" +interface IRepro +{ + void A(int value = 0); +} + +class Repro : IRepro +{ + public void [||]A(int value = 1) + { + } +}", +@" +interface IRepro +{ + void A(int value = 0); +} + +class Repro : IRepro +{ + void IRepro.A(int value = 1) + { + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [WorkItem(52020, "https://github.com/dotnet/roslyn/issues/52020")] + public async Task TestWithMismatchedDefault1() + { + await TestInRegularAndScriptAsync( + @" +interface IRepro +{ + void A(int value); +} + +class Repro : IRepro +{ + public void [||]A(int value = 1) + { + } +}", + @" +interface IRepro +{ + void A(int value); +} + +class Repro : IRepro +{ + void IRepro.A(int value = 1) + { + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + [WorkItem(52020, "https://github.com/dotnet/roslyn/issues/52020")] + public async Task TestWithMismatchedDefault2() + { + await TestInRegularAndScriptAsync( + @" +interface IRepro +{ + void A(int value = 0); +} + +class Repro : IRepro +{ + public void [||]A(int value) + { + } +}", + @" +interface IRepro +{ + void A(int value = 0); +} + +class Repro : IRepro +{ + void IRepro.A(int value) + { + } +}"); + } } } diff --git a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs index 66ffe34f3a66f..f072bdc5b8417 100644 --- a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs @@ -100,6 +100,7 @@ private static async Task TestInRegularAndScriptAsync( FixedCode = expectedMarkup, CodeActionEquivalenceKey = codeAction?.equivalenceKey, CodeActionIndex = codeAction?.index, + LanguageVersion = LanguageVersion.CSharp10, }.RunAsync(); } @@ -9381,6 +9382,103 @@ public void Bar(string? x) "); } + [WorkItem(53012, "https://github.com/dotnet/roslyn/issues/53012")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + public async Task TestNullableTypeParameter() + { + await TestInRegularAndScriptAsync( +@"#nullable enable + +interface I +{ + void M(T1? a, T2 b, T1? c, T3? d); +} + +class D : {|CS0535:I|} +{ +}", +@"#nullable enable + +interface I +{ + void M(T1? a, T2 b, T1? c, T3? d); +} + +class D : I +{ + public void M(T1? a, T2 b, T1? c, T3? d) + { + throw new System.NotImplementedException(); + } +}"); + } + + [WorkItem(53012, "https://github.com/dotnet/roslyn/issues/53012")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + public async Task TestNullableTypeParameter_ExplicitInterfaceImplementation() + { + await TestInRegularAndScriptAsync( +@"#nullable enable + +interface I +{ + void M(T1? a, T2 b, T1? c, T3? d); +} + +class D : {|CS0535:I|} +{ +}", +@"#nullable enable + +interface I +{ + void M(T1? a, T2 b, T1? c, T3? d); +} + +class D : I +{ + void I.M(T1? a, T2 b, T1? c, T3? d) + where T1 : default + where T3 : default + { + throw new System.NotImplementedException(); + } +}", codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + } + + [WorkItem(53012, "https://github.com/dotnet/roslyn/issues/53012")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + public async Task TestNullableTypeParameter_ExplicitInterfaceImplementationWithClassConstraint() + { + await TestInRegularAndScriptAsync( +@"#nullable enable + +interface I +{ + void M(T1? a, T2 b, T1? c, T3? d) where T1 : class; +} + +class D : {|CS0535:I|} +{ +}", +@"#nullable enable + +interface I +{ + void M(T1? a, T2 b, T1? c, T3? d) where T1 : class; +} + +class D : I +{ + void I.M(T1? a, T2 b, T1? c, T3? d) + where T1 : class + where T3 : default + { + throw new System.NotImplementedException(); + } +}", codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + } + [WorkItem(51779, "https://github.com/dotnet/roslyn/issues/51779")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task TestImplementTwoPropertiesOfCSharp5() diff --git a/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs b/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs index 7470bfef5aabb..cc1287e100ecb 100644 --- a/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs +++ b/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs @@ -1,24 +1,24 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.InitializeParameter; using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Testing; using Roslyn.Test.Utilities; using Xunit; -using VerifyCS = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.CSharpCodeRefactoringVerifier< - Microsoft.CodeAnalysis.CSharp.InitializeParameter.CSharpAddParameterCheckCodeRefactoringProvider>; - namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.InitializeParameter { + using VerifyCS = CSharpCodeRefactoringVerifier< + CSharpAddParameterCheckCodeRefactoringProvider>; + public class AddParameterCheckTests { [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] @@ -1663,6 +1663,58 @@ public C() }"); } + [WorkItem(20983, "https://github.com/dotnet/roslyn/issues/20983")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + public async Task TestOnDiscardLambdaParameter1() + { + await new VerifyCS.Test + { + LanguageVersion = LanguageVersionExtensions.CSharpNext, + TestCode = @" +using System; + +class C +{ + public C() + { + Func f = ([||]_) => { return 0; }; + } +}", + FixedCode = @" +using System; + +class C +{ + public C() + { + Func f = (_!!) => { return 0; }; + } +}" + }.RunAsync(); + } + + [WorkItem(20983, "https://github.com/dotnet/roslyn/issues/20983")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + public async Task TestOnDiscardLambdaParameter2() + { + var testCode = @" +using System; + +class C +{ + public C() + { + Func f = ([||]_, _) => { return 0; }; + } +}"; + await new VerifyCS.Test + { + LanguageVersion = LanguageVersionExtensions.CSharpNext, + TestCode = testCode, + FixedCode = testCode + }.RunAsync(); + } + [WorkItem(20983, "https://github.com/dotnet/roslyn/issues/20983")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] public async Task TestOnAnonymousMethodParameter() @@ -2722,5 +2774,112 @@ public C(object a, object b, object c) CodeActionEquivalenceKey = nameof(FeaturesResources.Add_null_checks_for_all_parameters) }.RunAsync(); } + + [WorkItem(58811, "https://github.com/dotnet/roslyn/issues/58811")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + public async Task TestMissingParameter1() + { + var source = @" +using System; + +class C +{ + public C(string s,[||]{|CS1031:{|CS1001:)|}|} + { + } +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); + } + + [WorkItem(58811, "https://github.com/dotnet/roslyn/issues/58811")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + public async Task TestMissingParameter2() + { + var source = @" +using System; + +class C +{ + public C(string s,[||] {|CS1031:{|CS1001:)|}|} + { + } +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); + } + + [WorkItem(58811, "https://github.com/dotnet/roslyn/issues/58811")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + public async Task TestMissingParameter3() + { + var source = @" +using System; + +class C +{ + public C(string s, [||]{|CS1031:{|CS1001:)|}|} + { + } +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); + } + + [WorkItem(58811, "https://github.com/dotnet/roslyn/issues/58811")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + public async Task TestMissingParameter4() + { + var source = @" +using System; + +class C +{ + public C(string s, [||] {|CS1031:{|CS1001:)|}|} + { + } +}"; + await VerifyCS.VerifyRefactoringAsync(source, source); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + [WorkItem(58779, "https://github.com/dotnet/roslyn/issues/58779")] + public async Task TestNotInRecordBeforeCSharp11() + { + var code = @" +record C([||]string s) { public string s; }"; + await new VerifyCS.Test + { + LanguageVersion = LanguageVersion.CSharp10, + TestCode = code, + FixedCode = code, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + [WorkItem(58779, "https://github.com/dotnet/roslyn/issues/58779")] + public async Task TestInRecordAfterCSharp11() + { + await new VerifyCS.Test + { + LanguageVersion = LanguageVersionExtensions.CSharpNext, + TestCode = @" +record C([||]string s) { public string s; }", + FixedCode = @" +record C(string s!!) { public string s; }", + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + [WorkItem(58779, "https://github.com/dotnet/roslyn/issues/58779")] + public async Task TestInRecordWithMultipleParametersAfterCSharp11() + { + await new VerifyCS.Test + { + LanguageVersion = LanguageVersionExtensions.CSharpNext, + TestCode = @" +record C([||]string s, string t) { public string s, t; }", + FixedCode = @" +record C(string s!!, string t!!) { public string s, t; }", + CodeActionIndex = 1, + }.RunAsync(); + } } } diff --git a/src/EditorFeatures/CSharpTest/IntroduceUsingStatement/IntroduceUsingStatementTests.cs b/src/EditorFeatures/CSharpTest/IntroduceUsingStatement/IntroduceUsingStatementTests.cs index 6c981b1683ab2..3b5a76c08bd61 100644 --- a/src/EditorFeatures/CSharpTest/IntroduceUsingStatement/IntroduceUsingStatementTests.cs +++ b/src/EditorFeatures/CSharpTest/IntroduceUsingStatement/IntroduceUsingStatementTests.cs @@ -143,6 +143,7 @@ void M(System.IDisposable disposable) using (var name = disposable) { } + var ignore = disposable; } }"); @@ -167,6 +168,7 @@ void M(System.IDisposable disposable) using (var name = disposable) { } + var ignore = disposable; } }"); @@ -417,6 +419,7 @@ void M(System.IDisposable disposable) M(null); M(x); } + M(null); } }"); @@ -478,6 +481,7 @@ void M(System.IDisposable disposable) { M(x); } + break; } } @@ -549,6 +553,7 @@ void M() var buffer = reader.GetBuffer(); buffer.Clone(); } + var a = 1; } }"); @@ -592,6 +597,7 @@ void M() var a = number; var b = a; } + var c = 1; } }"); @@ -635,6 +641,7 @@ void M() var a = number; var b = a; } + var c = 1; } }"); @@ -670,6 +677,7 @@ void M() int a = buffer[0], b = a; var c = b; } + var d = 1; } }"); diff --git a/src/EditorFeatures/CSharpTest/InvertIf/InvertIfTests.Elseless.cs b/src/EditorFeatures/CSharpTest/InvertIf/InvertIfTests.Elseless.cs index 106c03b2ab453..821b6b6843eba 100644 --- a/src/EditorFeatures/CSharpTest/InvertIf/InvertIfTests.Elseless.cs +++ b/src/EditorFeatures/CSharpTest/InvertIf/InvertIfTests.Elseless.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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; diff --git a/src/EditorFeatures/CSharpTest/InvertIf/InvertIfTests.cs b/src/EditorFeatures/CSharpTest/InvertIf/InvertIfTests.cs index fcbab10496bcc..117a43131bd33 100644 --- a/src/EditorFeatures/CSharpTest/InvertIf/InvertIfTests.cs +++ b/src/EditorFeatures/CSharpTest/InvertIf/InvertIfTests.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.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.InvertIf; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; using Microsoft.CodeAnalysis.Test.Utilities; @@ -1132,5 +1131,183 @@ void M(string s) } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvertIf)] + [WorkItem(51359, "https://github.com/dotnet/roslyn/issues/51359")] + public async Task TestIsCheck_CSharp6() + { + await TestInRegularAndScriptAsync( +@"class C +{ + int M() + { + [||]if (c is object) + { + return 1; + } + else + { + return 2; + } + } +}", +@"class C +{ + int M() + { + if (!(c is object)) + { + return 2; + } + else + { + return 1; + } + } +}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvertIf)] + [WorkItem(51359, "https://github.com/dotnet/roslyn/issues/51359")] + public async Task TestIsCheck_CSharp8() + { + await TestInRegularAndScriptAsync( +@"class C +{ + int M() + { + [||]if (c is object) + { + return 1; + } + else + { + return 2; + } + } +}", +@"class C +{ + int M() + { + if (c is null) + { + return 2; + } + else + { + return 1; + } + } +}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvertIf)] + [WorkItem(51359, "https://github.com/dotnet/roslyn/issues/51359")] + public async Task TestIsCheck_CSharp9() + { + await TestInRegularAndScriptAsync( +@"class C +{ + int M() + { + [||]if (c is object) + { + return 1; + } + else + { + return 2; + } + } +}", +@"class C +{ + int M() + { + if (c is null) + { + return 2; + } + else + { + return 1; + } + } +}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvertIf)] + [WorkItem(51359, "https://github.com/dotnet/roslyn/issues/51359")] + public async Task TestIsNotObjectCheck_CSharp8() + { + // Not terrific. But the starting code is not legal C#8 either. In this case because we don't even support + // 'not' patterns wee dont' bother diving into the pattern to negate it, and we instead just negate the + // expression. + await TestInRegularAndScriptAsync( +@"class C +{ + int M() + { + [||]if (c is not object) + { + return 1; + } + else + { + return 2; + } + } +}", +@"class C +{ + int M() + { + if (c is object) + { + return 2; + } + else + { + return 1; + } + } +}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvertIf)] + [WorkItem(51359, "https://github.com/dotnet/roslyn/issues/51359")] + public async Task TestIsNotObjectCheck_CSharp9() + { + await TestInRegularAndScriptAsync( +@"class C +{ + int M() + { + [||]if (c is not object) + { + return 1; + } + else + { + return 2; + } + } +}", +@"class C +{ + int M() + { + if (c is not null) + { + return 2; + } + else + { + return 1; + } + } +}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9)); + } } } diff --git a/src/EditorFeatures/CSharpTest/InvertLogical/InvertLogicalTests.cs b/src/EditorFeatures/CSharpTest/InvertLogical/InvertLogicalTests.cs index 25df7fa4ecb7b..3e62a030336c7 100644 --- a/src/EditorFeatures/CSharpTest/InvertLogical/InvertLogicalTests.cs +++ b/src/EditorFeatures/CSharpTest/InvertLogical/InvertLogicalTests.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.InvertLogical; -using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -18,6 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.InvertLogical { public partial class InvertLogicalTests : AbstractCSharpCodeActionTest { + private static readonly ParseOptions CSharp6 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6); private static readonly ParseOptions CSharp8 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8); private static readonly ParseOptions CSharp9 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9); @@ -355,7 +353,7 @@ void M(bool x, int a, object b) { void M(bool x, int a, object b) { - var c = !(a <= 10 || !(b is not string)); + var c = !(a <= 10 || b is string); } }", parseOptions: CSharp8); } @@ -423,6 +421,28 @@ void M(bool x, int a, object b) }", parseOptions: CSharp9); } + [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvertLogical)] + public async Task InvertIsNotNullPattern1_CSharp6() + { + // Result is illegal (uses a constant pattern in c# 6), but the original code was illegal as well. + await TestInRegularAndScriptAsync( +@"class C +{ + void M(bool x, int a, object b) + { + var c = a > 10 [||]&& b is not null; + } +}", +@"class C +{ + void M(bool x, int a, object b) + { + var c = !(a <= 10 || b is null); + } +}", parseOptions: CSharp6); + } + [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvertLogical)] public async Task InvertIsNotNullPattern1_CSharp8() @@ -439,7 +459,7 @@ void M(bool x, int a, object b) { void M(bool x, int a, object b) { - var c = !(a <= 10 || !(b is not null)); + var c = !(a <= 10 || b is null); } }", parseOptions: CSharp8); } @@ -670,7 +690,7 @@ void M(bool x, int a, object b) { void M(bool x, int a, object b) { - var c = !(a <= 10 || !(b is string s)); + var c = !(a <= 10 || b is not string s); } }", parseOptions: CSharp9); } diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncAnonymousFunctionHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncAnonymousFunctionHighlighterTests.cs index ecaaa6bffb6f3..d03af8c623344 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncAnonymousFunctionHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncAnonymousFunctionHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncLocalFunctionHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncLocalFunctionHighlighterTests.cs index 0647a8e842f8f..b59b2827b66f7 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncLocalFunctionHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncLocalFunctionHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncMethodHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncMethodHighlighterTests.cs index c9b4894e95b10..76917c5e5b247 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncMethodHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/AsyncMethodHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/AwaitHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/AwaitHighlighterTests.cs index a6c75be57af05..300f1103c6e8e 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/AwaitHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/AwaitHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/CheckedExpressionHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/CheckedExpressionHighlighterTests.cs index 9034c3deb51fc..bc3c0570f40be 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/CheckedExpressionHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/CheckedExpressionHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/CheckedStatementHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/CheckedStatementHighlighterTests.cs index 58f8af2e51008..18bd0fdee8783 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/CheckedStatementHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/CheckedStatementHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/ConditionalPreprocessorHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/ConditionalPreprocessorHighlighterTests.cs index b7171606cbcc3..01bb797507c44 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/ConditionalPreprocessorHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/ConditionalPreprocessorHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/IfStatementHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/IfStatementHighlighterTests.cs index 22b15c2e3b662..30443a665dca3 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/IfStatementHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/IfStatementHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/LockStatementHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/LockStatementHighlighterTests.cs index 62813c84f27b7..ef8642a61f3c0 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/LockStatementHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/LockStatementHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/LoopHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/LoopHighlighterTests.cs index b4729f056fe81..a27f23433bb10 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/LoopHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/LoopHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/RegionHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/RegionHighlighterTests.cs index 8219448963614..77c310d0c76e0 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/RegionHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/RegionHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/ReturnStatementHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/ReturnStatementHighlighterTests.cs index bdf6c8ae8740b..cf65cd3e02634 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/ReturnStatementHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/ReturnStatementHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/SwitchStatementHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/SwitchStatementHighlighterTests.cs index 24db56be4df9b..fa6a285d8907f 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/SwitchStatementHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/SwitchStatementHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/TryStatementHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/TryStatementHighlighterTests.cs index afad2b8916223..c1762c7706b9e 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/TryStatementHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/TryStatementHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/UnsafeStatementHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/UnsafeStatementHighlighterTests.cs index 39ecf6915ada0..77df94e89c128 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/UnsafeStatementHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/UnsafeStatementHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/UsingStatementHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/UsingStatementHighlighterTests.cs index b2aa410c16920..74ba97260300b 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/UsingStatementHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/UsingStatementHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/KeywordHighlighting/YieldStatementHighlighterTests.cs b/src/EditorFeatures/CSharpTest/KeywordHighlighting/YieldStatementHighlighterTests.cs index 5e31b69a46d93..174d90e0eacb5 100644 --- a/src/EditorFeatures/CSharpTest/KeywordHighlighting/YieldStatementHighlighterTests.cs +++ b/src/EditorFeatures/CSharpTest/KeywordHighlighting/YieldStatementHighlighterTests.cs @@ -6,7 +6,7 @@ using System; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters; +using Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/LineSeparators/LineSeparatorTests.cs b/src/EditorFeatures/CSharpTest/LineSeparators/LineSeparatorTests.cs index af729ac384545..e46a24df82087 100644 --- a/src/EditorFeatures/CSharpTest/LineSeparators/LineSeparatorTests.cs +++ b/src/EditorFeatures/CSharpTest/LineSeparators/LineSeparatorTests.cs @@ -7,8 +7,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Editor.CSharp.LineSeparator; +using Microsoft.CodeAnalysis.CSharp.LineSeparators; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.LineSeparators; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; diff --git a/src/EditorFeatures/CSharpTest/Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj b/src/EditorFeatures/CSharpTest/Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj index 83e7d128c62aa..57f6b2f582f6c 100644 --- a/src/EditorFeatures/CSharpTest/Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj +++ b/src/EditorFeatures/CSharpTest/Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj @@ -67,9 +67,6 @@ - - - diff --git a/src/EditorFeatures/CSharpTest/MoveStaticMembers/CSharpMoveStaticMembersTests.cs b/src/EditorFeatures/CSharpTest/MoveStaticMembers/CSharpMoveStaticMembersTests.cs index 2aa3ae48d95aa..06611eeb08b5f 100644 --- a/src/EditorFeatures/CSharpTest/MoveStaticMembers/CSharpMoveStaticMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/MoveStaticMembers/CSharpMoveStaticMembersTests.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.MoveStaticMembers; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities.MoveStaticMembers; @@ -2566,16 +2567,32 @@ public class Class1 } #endregion + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMoveStaticMembers)] + public async Task NoOptionsService_NoAction() + { + var initialMarkup = @" +namespace TestNs1 +{ + public class Class1 + { + public static int TestField = 1;[||] + } +}"; + await TestNoRefactoringAsync(initialMarkup, hostServices: FeaturesTestCompositions.Features.GetHostServices()).ConfigureAwait(false); + } + private class Test : VerifyCS.Test { public Test( string destinationType, ImmutableArray selection, - string destinationName = "a.cs") + string destinationName = "a.cs", + HostServices? hostServices = null) { _destinationType = destinationType; _selection = selection; _destinationName = destinationName; + _hostServices = hostServices; } private readonly string _destinationType; @@ -2584,15 +2601,20 @@ public Test( private readonly string _destinationName; + private readonly HostServices? _hostServices; + protected override Workspace CreateWorkspaceImpl() { - var hostServices = s_testServices.GetHostServices(); + var hostServices = _hostServices ?? s_testServices.GetHostServices(); var workspace = new AdhocWorkspace(hostServices); - var testOptionsService = (TestMoveStaticMembersService)workspace.Services.GetRequiredService(); - testOptionsService.DestinationType = _destinationType; - testOptionsService.SelectedMembers = _selection; - testOptionsService.Filename = _destinationName; + var testOptionsService = workspace.Services.GetService() as TestMoveStaticMembersService; + if (testOptionsService is not null) + { + testOptionsService.DestinationType = _destinationType; + testOptionsService.SelectedMembers = _selection; + testOptionsService.Filename = _destinationName; + } return workspace; } @@ -2618,9 +2640,9 @@ private static async Task TestMovementNewFileAsync( }, }.RunAsync().ConfigureAwait(false); - private static async Task TestNoRefactoringAsync(string initialMarkup) + private static async Task TestNoRefactoringAsync(string initialMarkup, HostServices? hostServices = null) { - await new Test("", ImmutableArray.Empty) + await new Test("", ImmutableArray.Empty, hostServices: hostServices) { TestCode = initialMarkup, FixedCode = initialMarkup, diff --git a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs index 0aa8e949a25e4..7f9280b87f71c 100644 --- a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs +++ b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs @@ -1504,6 +1504,72 @@ public partial class C }, await _aggregator.GetItemsAsync("C")); } + + [Theory, CombinatorialData] + [WorkItem(59231, "https://github.com/dotnet/roslyn/issues/59231")] + public async Task FindMethodWithTuple(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @"class Goo +{ + public void Method( + (int x, Dictionary y) t1, + (bool b, global::System.Int32 c) t2) + { + } +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Method")).Single(); + VerifyNavigateToResultItem(item, "Method", "[|Method|]((int x, Dictionary y), (bool b, global::System.Int32 c))", PatternMatchKind.Exact, NavigateToItemKind.Method, Glyph.MethodPublic, string.Format(FeaturesResources.in_0_project_1, "Goo", "Test")); +}); + } + + [Theory] + [CombinatorialData] + [WorkItem(57873, "https://github.com/dotnet/roslyn/issues/57873")] + public async Task FindRecordMember1(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @"record Goo(int Member) +{ +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Member")).Single(x => x.Kind == NavigateToItemKind.Property); + VerifyNavigateToResultItem(item, "Member", "[|Member|]", PatternMatchKind.Exact, NavigateToItemKind.Property, Glyph.PropertyPublic); +}); + } + + [Theory] + [CombinatorialData] + [WorkItem(57873, "https://github.com/dotnet/roslyn/issues/57873")] + public async Task FindRecordMember2(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @"record Goo(int Member) +{ + public int Member { get; } = Member; +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Member")).Single(x => x.Kind == NavigateToItemKind.Property); + VerifyNavigateToResultItem(item, "Member", "[|Member|]", PatternMatchKind.Exact, NavigateToItemKind.Property, Glyph.PropertyPublic); +}); + } + + [Theory] + [CombinatorialData] + [WorkItem(57873, "https://github.com/dotnet/roslyn/issues/57873")] + public async Task FindRecordMember3(TestHost testHost, Composition composition) + { + await TestAsync( +testHost, composition, @"record Goo(int Member) +{ + public int Member = Member; +}", async w => +{ + var item = (await _aggregator.GetItemsAsync("Member")).Single(x => x.Kind == NavigateToItemKind.Field); + VerifyNavigateToResultItem(item, "Member", "[|Member|]", PatternMatchKind.Exact, NavigateToItemKind.Field, Glyph.FieldPublic); +}); + } } } #pragma warning restore CS0618 // MatchKind is obsolete diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs index 4cc1bff1419f7..3655a1a69ac16 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs @@ -96,17 +96,18 @@ protected static async Task TestAsync( buildReferenceAssembly, windowsPdb: false); - await GenerateFileAndVerifyAsync(project, symbol, source, expectedSpan, expectNullResult); + await GenerateFileAndVerifyAsync(project, symbol, sourceLocation, source, expectedSpan, expectNullResult); } protected static async Task GenerateFileAndVerifyAsync( Project project, ISymbol symbol, + Location sourceLocation, string expected, Text.TextSpan expectedSpan, bool expectNullResult) { - var (actual, actualSpan) = await GetGeneratedSourceTextAsync(project, symbol, expectNullResult); + var (actual, actualSpan) = await GetGeneratedSourceTextAsync(project, symbol, sourceLocation, expectNullResult); if (actual is null) return; @@ -121,6 +122,7 @@ protected static async Task GenerateFileAndVerifyAsync( protected static async Task<(SourceText?, TextSpan)> GetGeneratedSourceTextAsync( Project project, ISymbol symbol, + Location sourceLocation, bool expectNullResult) { using var workspace = (TestWorkspace)project.Solution.Workspace; @@ -140,6 +142,15 @@ protected static async Task GenerateFileAndVerifyAsync( Assert.NotSame(NullResultMetadataAsSourceFileProvider.NullResult, file); } + if (sourceLocation == Location.OnDisk) + { + Assert.True(file.DocumentTitle.Contains($"[{FeaturesResources.external}]")); + } + else + { + Assert.True(file.DocumentTitle.Contains($"[{FeaturesResources.embedded}]")); + } + AssertEx.NotNull(file, $"No source document was found in the pdb for the symbol."); var masWorkspace = service.TryGetWorkspace(); diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbFileLocatorServiceTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbFileLocatorServiceTests.cs index 872a5f14cbd59..ee1af8cbb24f0 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbFileLocatorServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbFileLocatorServiceTests.cs @@ -34,9 +34,9 @@ await RunTestAsync(async path => File.Move(GetPdbPath(path), pdbFilePath); var sourceLinkService = new TestSourceLinkService(pdbFilePath: pdbFilePath); - var service = new PdbFileLocatorService(sourceLinkService); + var service = new PdbFileLocatorService(sourceLinkService, logger: null); - using var result = await service.GetDocumentDebugInfoReaderAsync(GetDllPath(path), logger: null, CancellationToken.None); + using var result = await service.GetDocumentDebugInfoReaderAsync(GetDllPath(path), new TelemetryMessage(CancellationToken.None), CancellationToken.None); Assert.NotNull(result); }); @@ -55,16 +55,18 @@ await RunTestAsync(async path => { MarkupTestFile.GetSpan(source, out var metadataSource, out var expectedSpan); - var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.OnDisk, Location.OnDisk, metadataSource, c => c.GetMember("C.E")); + // Ideally we don't want to pass in true for windowsPdb here, and this is supposed to test that the service ignores non-portable PDBs when the debugger + // tells us they're not portable, but the debugger has a bug at the moment. + var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.OnDisk, Location.OnDisk, metadataSource, c => c.GetMember("C.E"), windowsPdb: true); // Move the PDB to a path that only our fake debugger service knows about var pdbFilePath = Path.Combine(path, "SourceLink.pdb"); File.Move(GetPdbPath(path), pdbFilePath); - var sourceLinkService = new TestSourceLinkService(pdbFilePath: pdbFilePath, isPortablePdb: false); - var service = new PdbFileLocatorService(sourceLinkService); + var sourceLinkService = new TestSourceLinkService(pdbFilePath); + var service = new PdbFileLocatorService(sourceLinkService, logger: null); - using var result = await service.GetDocumentDebugInfoReaderAsync(GetDllPath(path), logger: null, CancellationToken.None); + using var result = await service.GetDocumentDebugInfoReaderAsync(GetDllPath(path), new TelemetryMessage(CancellationToken.None), CancellationToken.None); Assert.Null(result); }); @@ -90,9 +92,9 @@ await RunTestAsync(async path => File.Move(GetPdbPath(path), pdbFilePath); var sourceLinkService = new TestSourceLinkService(pdbFilePath: null); - var service = new PdbFileLocatorService(sourceLinkService); + var service = new PdbFileLocatorService(sourceLinkService, logger: null); - using var result = await service.GetDocumentDebugInfoReaderAsync(GetDllPath(path), logger: null, CancellationToken.None); + using var result = await service.GetDocumentDebugInfoReaderAsync(GetDllPath(path), new TelemetryMessage(CancellationToken.None), CancellationToken.None); Assert.Null(result); }); diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs index 844e8b58681d1..aad7f09787ae7 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs @@ -38,13 +38,13 @@ await RunTestAsync(async path => File.Move(GetSourceFilePath(path), sourceFilePath); var sourceLinkService = new Lazy(() => new TestSourceLinkService(sourceFilePath: sourceFilePath)); - var service = new PdbSourceDocumentLoaderService(sourceLinkService); + var service = new PdbSourceDocumentLoaderService(sourceLinkService, logger: null); using var hash = SHA256.Create(); var fileHash = hash.ComputeHash(File.ReadAllBytes(sourceFilePath)); var sourceDocument = new SourceDocument("goo.cs", Text.SourceHashAlgorithm.Sha256, fileHash.ToImmutableArray(), null, "https://sourcelink"); - var result = await service.LoadSourceDocumentAsync(path, sourceDocument, Encoding.UTF8, logger: null, CancellationToken.None); + var result = await service.LoadSourceDocumentAsync(path, sourceDocument, Encoding.UTF8, new TelemetryMessage(CancellationToken.None), CancellationToken.None); Assert.NotNull(result); Assert.Equal(sourceFilePath, result!.FilePath); @@ -71,10 +71,10 @@ await RunTestAsync(async path => File.Move(GetSourceFilePath(path), sourceFilePath); var sourceLinkService = new Lazy(() => new TestSourceLinkService(sourceFilePath: sourceFilePath)); - var service = new PdbSourceDocumentLoaderService(sourceLinkService); + var service = new PdbSourceDocumentLoaderService(sourceLinkService, logger: null); var sourceDocument = new SourceDocument("goo.cs", Text.SourceHashAlgorithm.None, default, null, SourceLinkUrl: null); - var result = await service.LoadSourceDocumentAsync(path, sourceDocument, Encoding.UTF8, logger: null, CancellationToken.None); + var result = await service.LoadSourceDocumentAsync(path, sourceDocument, Encoding.UTF8, new TelemetryMessage(CancellationToken.None), CancellationToken.None); Assert.Null(result); }); diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs index 16c13ec0302a8..81549ce6025f8 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs @@ -401,7 +401,7 @@ await RunTestAsync(async path => // Now delete the PDB File.Delete(GetPdbPath(path)); - await GenerateFileAndVerifyAsync(project, symbol, source, expectedSpan, expectNullResult: true); + await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); } @@ -423,7 +423,7 @@ await RunTestAsync(async path => // Now delete the DLL File.Delete(GetDllPath(path)); - await GenerateFileAndVerifyAsync(project, symbol, source, expectedSpan, expectNullResult: true); + await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); } @@ -444,7 +444,7 @@ await RunTestAsync(async path => // Now delete the source File.Delete(GetSourceFilePath(path)); - await GenerateFileAndVerifyAsync(project, symbol, source, expectedSpan, expectNullResult: true); + await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); } @@ -463,7 +463,7 @@ await RunTestAsync(async path => var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.OnDisk, Location.OnDisk, metadataSource, c => c.GetMember("C.E"), windowsPdb: true); //TODO: This should not be a null result: https://github.com/dotnet/roslyn/issues/55834 - await GenerateFileAndVerifyAsync(project, symbol, source, expectedSpan, expectNullResult: true); + await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); } @@ -485,7 +485,7 @@ await RunTestAsync(async path => // Now make the PDB a zero byte file File.WriteAllBytes(GetPdbPath(path), new byte[0]); - await GenerateFileAndVerifyAsync(project, symbol, source, expectedSpan, expectNullResult: true); + await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); } @@ -509,7 +509,7 @@ await RunTestAsync(async path => var corruptPdb = new byte[] { 66, 83, 74, 66, 68, 87 }; File.WriteAllBytes(GetPdbPath(path), corruptPdb); - await GenerateFileAndVerifyAsync(project, symbol, source, expectedSpan, expectNullResult: true); + await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source, expectedSpan, expectNullResult: true); }); } @@ -545,7 +545,7 @@ await RunTestAsync(async path => File.Delete(pdbFilePath); File.Move(archivePdbFilePath, pdbFilePath); - await GenerateFileAndVerifyAsync(project, symbol, source1, expectedSpan, expectNullResult: true); + await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, source1, expectedSpan, expectNullResult: true); }); } @@ -573,7 +573,7 @@ await RunTestAsync(async path => File.WriteAllText(GetSourceFilePath(path), source2, Encoding.UTF8); - await GenerateFileAndVerifyAsync(project, symbol, metadataSource, expectedSpan, expectNullResult: true); + await GenerateFileAndVerifyAsync(project, symbol, Location.OnDisk, metadataSource, expectedSpan, expectNullResult: true); }); } @@ -609,7 +609,7 @@ await RunTestAsync(async path => var (project, symbol) = await CompileAndFindSymbolAsync(path, pdbLocation, Location.Embedded, encodedSourceText, c => c.GetMember("C.E")); - var (actualText, _) = await GetGeneratedSourceTextAsync(project, symbol, expectNullResult: false); + var (actualText, _) = await GetGeneratedSourceTextAsync(project, symbol, Location.Embedded, expectNullResult: false); AssertEx.NotNull(actualText); AssertEx.NotNull(actualText.Encoding); @@ -638,7 +638,7 @@ await RunTestAsync(async path => var (project, symbol) = await CompileAndFindSymbolAsync(path, pdbLocation, Location.Embedded, encodedSourceText, c => c.GetMember("C.E")); - var (actualText, _) = await GetGeneratedSourceTextAsync(project, symbol, expectNullResult: false); + var (actualText, _) = await GetGeneratedSourceTextAsync(project, symbol, Location.Embedded, expectNullResult: false); AssertEx.NotNull(actualText); AssertEx.NotNull(actualText.Encoding); @@ -667,7 +667,7 @@ await RunTestAsync(async path => var (project, symbol) = await CompileAndFindSymbolAsync(path, pdbLocation, Location.Embedded, encodedSourceText, c => c.GetMember("C.E"), fallbackEncoding: encoding); - var (actualText, _) = await GetGeneratedSourceTextAsync(project, symbol, expectNullResult: false); + var (actualText, _) = await GetGeneratedSourceTextAsync(project, symbol, Location.Embedded, expectNullResult: false); AssertEx.NotNull(actualText); AssertEx.NotNull(actualText.Encoding); diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/TestSourceLinkService.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/TestSourceLinkService.cs index 87918089e5ac7..6cc3573b5b292 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/TestSourceLinkService.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/TestSourceLinkService.cs @@ -13,33 +13,31 @@ internal class TestSourceLinkService : ISourceLinkService { private readonly string? _pdbFilePath; private readonly string? _sourceFilePath; - private readonly bool _isPortablePdb; - public TestSourceLinkService(string? pdbFilePath = null, string? sourceFilePath = null, bool isPortablePdb = true) + public TestSourceLinkService(string? pdbFilePath = null, string? sourceFilePath = null) { _pdbFilePath = pdbFilePath; _sourceFilePath = sourceFilePath; - _isPortablePdb = isPortablePdb; } - public Task GetPdbFilePathAsync(string dllPath, PEReader peReader, IPdbSourceDocumentLogger? logger, CancellationToken cancellationToken) + public Task GetPdbFilePathAsync(string dllPath, PEReader peReader, CancellationToken cancellationToken) { if (_pdbFilePath is null) { return Task.FromResult(null); } - return Task.FromResult(new PdbFilePathResult(_pdbFilePath, "status", Log: null, _isPortablePdb)); + return Task.FromResult(new PdbFilePathResult(_pdbFilePath)); } - public Task GetSourceFilePathAsync(string url, string relativePath, IPdbSourceDocumentLogger? logger, CancellationToken cancellationToken) + public Task GetSourceFilePathAsync(string url, string relativePath, CancellationToken cancellationToken) { if (_sourceFilePath is null) { return Task.FromResult(null); } - return Task.FromResult(new SourceFilePathResult(_sourceFilePath, Log: null)); + return Task.FromResult(new SourceFilePathResult(_sourceFilePath)); } } } diff --git a/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs b/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs index 81bcfdbc3da5b..2623c19486ad4 100644 --- a/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs +++ b/src/EditorFeatures/CSharpTest/PullMemberUp/CSharpPullMemberUpTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.PullMemberUp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; @@ -19,6 +20,7 @@ using Microsoft.CodeAnalysis.Test.Utilities.PullMemberUp; using Roslyn.Test.Utilities; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.PullMemberUp { @@ -35,6 +37,9 @@ private async Task TestQuickActionNotProvidedAsync( string initialMarkup, TestParameters parameters = default) { + var service = new TestPullMemberUpService(null, null); + parameters = parameters.WithFixProviderData(service); + using var workspace = CreateWorkspaceFromOptions(initialMarkup, parameters); var (actions, _) = await GetCodeActionsAsync(workspace, parameters); if (actions.Length == 1) @@ -52,6 +57,28 @@ private async Task TestQuickActionNotProvidedAsync( } } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] + public async Task TestNoRefactoringProvidedWhenNoOptionsService() + { + var testText = @" +using System; +namespace PushUpTest +{ + interface IInterface + { + } + + public class TestClass : IInterface + { + public void TestM[||]ethod() + { + System.Console.WriteLine(""Hello World""); + } + } +}"; + await TestActionCountAsync(testText, 0); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] public async Task TestNoRefactoringProvidedWhenPullFieldInInterfaceViaQuickAction() { @@ -190,7 +217,7 @@ public void TestMethod() } } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -222,7 +249,7 @@ public abstract class TestClass : IInterface public abstract void TestMethod(); } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -260,7 +287,7 @@ public class TestClass : IInterface } } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -314,7 +341,7 @@ public event EventHandler Event1 } } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -348,7 +375,7 @@ public class TestClass : IInterface public event EventHandler Event1, Event2, Event3; } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -402,7 +429,7 @@ public event EventHandler Event2 } } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -436,7 +463,7 @@ public class TestClass : IInterface public int TestProperty { get; private set; } } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -470,7 +497,7 @@ public class TestClass : IInterface public int TestProperty{ private get; set; } } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -503,7 +530,7 @@ interface FooInterface : IInterface { } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -544,7 +571,7 @@ public int this[int i] } } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -585,7 +612,7 @@ public int this[int i] } } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -633,7 +660,7 @@ public class Derived : IBase "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -689,7 +716,7 @@ public class Derived : IBase "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -743,7 +770,7 @@ public Uri TestMethod() "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -799,7 +826,7 @@ public bool TestMethod(Uri endpoint) "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -867,7 +894,7 @@ public event EventHandler TestEvent "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -913,7 +940,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -957,7 +984,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1006,7 +1033,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1068,7 +1095,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1120,7 +1147,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1192,7 +1219,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1260,7 +1287,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1320,7 +1347,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1375,7 +1402,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1427,7 +1454,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1479,7 +1506,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1538,7 +1565,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1598,7 +1625,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1676,7 +1703,7 @@ public class Foo "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1753,7 +1780,7 @@ public class Foo "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1843,7 +1870,7 @@ public static int FooBar(this Foo foo) "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -1958,7 +1985,7 @@ public static int FooBar(this Foo foo) "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2019,7 +2046,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2077,7 +2104,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2133,7 +2160,7 @@ public class Derived : Base } } "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2218,7 +2245,7 @@ public static int Bar(int num) } } "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2280,7 +2307,7 @@ class Other "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2336,7 +2363,7 @@ class Other "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2397,7 +2424,7 @@ class Other "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2458,7 +2485,7 @@ public class Derived : Base } } "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2522,7 +2549,7 @@ public class Derived : Base } } "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2592,7 +2619,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2664,7 +2691,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2716,7 +2743,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2770,7 +2797,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2826,7 +2853,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2892,7 +2919,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2938,7 +2965,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -2984,7 +3011,7 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3126,7 +3153,7 @@ public class TestClass : Base { } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3157,7 +3184,7 @@ public class TestClass : Base { } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3194,7 +3221,7 @@ public class TestClass : BaseClass { } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3226,7 +3253,7 @@ public class TestClass : Base public int you, someone = 10086; } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3257,7 +3284,7 @@ public class TestClass : Base public int you, someone = 10086; } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3292,7 +3319,7 @@ public class Testclass2 : Base2 private static event EventHandler Event1, Event4; } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3326,7 +3353,7 @@ public class TestClass2 : Base2 { } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3380,7 +3407,7 @@ public class TestClass2 : Base2 { } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3413,7 +3440,7 @@ public class TestClass : Base { } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3454,7 +3481,7 @@ public class TestClass : Base private int j; } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3514,7 +3541,7 @@ public interface IInterface "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3576,7 +3603,7 @@ public interface IInterface "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3630,7 +3657,7 @@ public class BaseClass "; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3886,10 +3913,10 @@ public class Derived : Base "; - await TestInRegularAndScriptAsync( + await TestWithPullMemberDialogAsync( testText, expected, - options: Option(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, CodeAnalysis.AddImports.AddImportPlacement.InsideNamespace, CodeStyle.NotificationOption2.Silent)); + options: Option(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, AddImportPlacement.InsideNamespace, CodeStyle.NotificationOption2.Silent)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -3976,7 +4003,7 @@ public Goo(String s) "; - await TestInRegularAndScriptAsync( + await TestWithPullMemberDialogAsync( testText, expected, options: new(GetLanguage()) @@ -4012,7 +4039,7 @@ public class Bar : BaseClass #region Hello #endregion }"; - return TestInRegularAndScriptAsync(text, expected); + return TestWithPullMemberDialogAsync(text, expected); } [Fact] @@ -4043,7 +4070,7 @@ public class Bar : BaseClass public void Goo() { } #endregion }"; - return TestInRegularAndScriptAsync(text, expected); + return TestWithPullMemberDialogAsync(text, expected); } [Fact] @@ -4077,7 +4104,7 @@ public void Hello() { } #region Hello #endregion }"; - return TestInRegularAndScriptAsync(text, expected); + return TestWithPullMemberDialogAsync(text, expected); } [Fact] @@ -4108,7 +4135,7 @@ public class Bar : BaseClass public int Goo = 10; #endregion }"; - return TestInRegularAndScriptAsync(text, expected); + return TestWithPullMemberDialogAsync(text, expected); } [Fact] @@ -4140,7 +4167,7 @@ public class Bar : BaseClass #region Hello #endregion }"; - return TestInRegularAndScriptAsync(text, expected); + return TestWithPullMemberDialogAsync(text, expected); } [Fact] @@ -4170,7 +4197,7 @@ public class Bar : BaseClass public int Hoo; #endregion }"; - return TestInRegularAndScriptAsync(text, expected); + return TestWithPullMemberDialogAsync(text, expected); } [Fact] @@ -4202,7 +4229,7 @@ public class Bar : BaseClass #region Hello #endregion }"; - return TestInRegularAndScriptAsync(text, expected); + return TestWithPullMemberDialogAsync(text, expected); } [Fact] @@ -4232,7 +4259,7 @@ public class Bar : BaseClass #region Hello #endregion }"; - return TestInRegularAndScriptAsync(text, expected); + return TestWithPullMemberDialogAsync(text, expected); } #endregion Quick Action @@ -4245,14 +4272,15 @@ internal Task TestWithPullMemberDialogAsync( IEnumerable<(string name, bool makeAbstract)> selection = null, string destinationName = null, int index = 0, - TestParameters parameters = default) + TestParameters parameters = default, + OptionsCollection options = null) { var service = new TestPullMemberUpService(selection, destinationName); return TestInRegularAndScript1Async( initialMarkUp, expectedResult, index, - parameters.WithFixProviderData(service)); + parameters.WithFixProviderData(service).WithOptions(options)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5211,7 +5239,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5259,7 +5287,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5330,7 +5358,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5374,7 +5402,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5419,7 +5447,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5621,7 +5649,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5673,7 +5701,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5709,7 +5737,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5745,7 +5773,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5783,7 +5811,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5825,7 +5853,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPullMemberUp)] @@ -5867,7 +5895,7 @@ public class B : A } }"; - await TestInRegularAndScriptAsync(testText, expected); + await TestWithPullMemberDialogAsync(testText, expected); } #endregion diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index bd6fa8efe567f..046a3fe451a93 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -14,6 +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.QuickInfo; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -65,7 +66,7 @@ private static async Task TestWithOptionsAsync(TestWorkspace workspace, params A private static async Task TestWithOptionsAsync(Document document, QuickInfoService service, int position, Action[] expectedResults) { - var info = await service.GetQuickInfoAsync(document, position, cancellationToken: CancellationToken.None); + var info = await service.GetQuickInfoAsync(document, position, SymbolDescriptionOptions.Default, CancellationToken.None); if (expectedResults.Length == 0) { @@ -100,7 +101,7 @@ private static async Task VerifyWithMscorlib45Async(string markup, ActionThe person's first name. +record Person(string First, string Last) +{ + void M(Person p) + { + _ = p.$$First; + } +}", + MainDescription("string Person.First { get; init; }"), + Documentation("The person's first name.")); + } + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] [WorkItem(51615, "https://github.com/dotnet/roslyn/issues/51615")] public async Task TestVarPatternOnVarKeyword() @@ -7914,6 +7932,23 @@ void M() TResult {FeaturesResources.is_} string")); } + [WorkItem(58871, "https://github.com/dotnet/roslyn/issues/58871")] + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestInferredNonAnonymousDelegateType1() + { + await TestAsync( +@"class C +{ + void M() + { + $$var v = (int i) => i.ToString(); + } +}", + MainDescription("delegate TResult System.Func(T arg)"), + AnonymousTypes("")); + } + + [WorkItem(58871, "https://github.com/dotnet/roslyn/issues/58871")] [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] public async Task TestAnonymousSynthesizedLambdaType() { @@ -7925,7 +7960,49 @@ void M() $$var v = (ref int i) => i.ToString(); } }", - MainDescription("delegate string (ref int)")); + MainDescription("delegate string (ref int)"), + AnonymousTypes("")); + } + + [WorkItem(58871, "https://github.com/dotnet/roslyn/issues/58871")] + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestAnonymousSynthesizedLambdaType2() + { + await TestAsync( +@"class C +{ + void M() + { + var $$v = (ref int i) => i.ToString(); + } +}", + MainDescription($"({FeaturesResources.local_variable}) 'a v"), + AnonymousTypes( +$@" +{FeaturesResources.Types_colon} + 'a {FeaturesResources.is_} delegate string (ref int)")); + } + + [WorkItem(58871, "https://github.com/dotnet/roslyn/issues/58871")] + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestAnonymousSynthesizedLambdaType3() + { + await TestAsync( +@"class C +{ + void M() + { + var v = (ref int i) => i.ToString(); + $$Goo(v); + } + + T Goo(T t) => default; +}", + MainDescription("'a C.Goo<'a>('a t)"), + AnonymousTypes( +$@" +{FeaturesResources.Types_colon} + 'a {FeaturesResources.is_} delegate string (ref int)")); } [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] @@ -8055,5 +8132,65 @@ void N() 'a {FeaturesResources.is_} new {{ 'b x, 'b y }} 'b {FeaturesResources.is_} (int a, string b)")); } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestInRawStringInterpolation_SingleLine() + { + await TestInMethodAsync( +@"var x = 1; +var s = $""""""Hello world {$$x}""""""", + MainDescription($"({FeaturesResources.local_variable}) int x")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestInRawStringInterpolation_SingleLine_MultiBrace() + { + await TestInMethodAsync( +@"var x = 1; +var s = ${|#0:|}$""""""Hello world {{$$x}}""""""", + MainDescription($"({FeaturesResources.local_variable}) int x")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestInRawStringLiteral_SingleLine_Const() + { + await TestInClassAsync( +@"const string $$s = """"""Hello world""""""", + MainDescription(@$"({FeaturesResources.constant}) string C.s = """"""Hello world""""""")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestInRawStringInterpolation_MultiLine() + { + await TestInMethodAsync( +@"var x = 1; +var s = $"""""" +Hello world {$$x} +""""""", + MainDescription($"({FeaturesResources.local_variable}) int x")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestInRawStringInterpolation_MultiLine_MultiBrace() + { + await TestInMethodAsync( +@"var x = 1; +var s = ${|#0:|}$"""""" +Hello world {{$$x}} +""""""", + MainDescription($"({FeaturesResources.local_variable}) int x")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestInRawStringLiteral_MultiLine_Const() + { + await TestInClassAsync( +@"const string $$s = """""" + Hello world + """"""", + MainDescription(@$"({FeaturesResources.constant}) string C.s = """""" + Hello world + """"""")); + } } } diff --git a/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs new file mode 100644 index 0000000000000..f03f8829765f1 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs @@ -0,0 +1,378 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Xml.Linq; +using Microsoft.CodeAnalysis.Editor.CSharp.CompleteStatement; +using Microsoft.CodeAnalysis.Editor.CSharp.RawStringLiteral; +using Microsoft.CodeAnalysis.Editor.Shared.Options; +using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.VisualStudio.Commanding; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.RawStringLiteral +{ + [UseExportProvider] + public class RawStringLiteralCommandHandlerTests + { + internal sealed class RawStringLiteralTestState : AbstractCommandHandlerTestState + { + private static readonly TestComposition s_composition = EditorTestCompositions.EditorFeaturesWpf.AddParts( + typeof(RawStringLiteralCommandHandler)); + + private readonly RawStringLiteralCommandHandler _commandHandler; + + public RawStringLiteralTestState(XElement workspaceElement) + : base(workspaceElement, s_composition) + { + _commandHandler = (RawStringLiteralCommandHandler)GetExportedValues(). + Single(c => c is RawStringLiteralCommandHandler); + } + + public static RawStringLiteralTestState CreateTestState(string markup) + => new(GetWorkspaceXml(markup)); + + public static XElement GetWorkspaceXml(string markup) + => XElement.Parse(string.Format(@" + + + {0} + +", markup)); + + internal void AssertCodeIs(string expectedCode) + { + MarkupTestFile.GetPositionAndSpans(expectedCode, out var massaged, out int? caretPosition, out var spans); + Assert.Equal(massaged, TextView.TextSnapshot.GetText()); + Assert.Equal(caretPosition!.Value, TextView.Caret.Position.BufferPosition.Position); + + var virtualSpaces = spans.SingleOrDefault(kvp => kvp.Key.StartsWith("VirtualSpaces#")); + if (virtualSpaces.Key != null) + { + var virtualOffset = int.Parse(virtualSpaces.Key.Substring("VirtualSpaces-".Length)); + Assert.True(TextView.Caret.InVirtualSpace); + Assert.Equal(virtualOffset, TextView.Caret.Position.VirtualBufferPosition.VirtualSpaces); + } + } + + public void SendTypeChar(char ch) + => SendTypeChar(ch, _commandHandler.ExecuteCommand, () => EditorOperations.InsertText(ch.ToString())); + + public void SendReturn(bool handled) + => SendReturn(_commandHandler.ExecuteCommand, () => + { + Assert.False(handled, "Return key should have been handled"); + }); + } + + #region enter tests + + [WpfFact] + public void TestReturnInSixQuotes() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"""$$"""""""); + + testState.SendReturn(handled: true); + testState.AssertCodeIs( +@"var v = """""" +$${|VirtualSpaces-4:|} + """""""); + } + + [WpfFact] + public void TestReturnInSixQuotesWithSemicolonAfter() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"""$$"""""";"); + + testState.SendReturn(handled: true); + testState.AssertCodeIs( +@"var v = """""" +$${|VirtualSpaces-4:|} + """""";"); + } + + [WpfFact] + public void TestReturnInSixQuotesNotAtMiddle() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"""""$$"""""); + + testState.SendReturn(handled: false); + testState.AssertCodeIs( +@"var v = """"""""$$"""""); + } + + [WpfFact] + public void TestReturnInSixQuotes_Interpolated() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = $""""""$$"""""""); + + testState.SendReturn(handled: true); + testState.AssertCodeIs( +@"var v = $"""""" +$${|VirtualSpaces-4:|} + """""""); + } + + [WpfFact] + public void TestReturnInSixQuotesWithSemicolonAfter_Interpolated() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = $""""""$$"""""";"); + + testState.SendReturn(handled: true); + testState.AssertCodeIs( +@"var v = $"""""" +$${|VirtualSpaces-4:|} + """""";"); + } + + [WpfFact] + public void TestReturnInSixQuotesNotAtMiddle_Interpolated() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = $""""""""$$"""""); + + testState.SendReturn(handled: false); + testState.AssertCodeIs( +@"var v = $""""""""$$"""""); + } + + [WpfFact] + public void TestReturnEndOfFile() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"""$$"); + + testState.SendReturn(handled: false); + } + + [WpfFact] + public void TestReturnInEmptyFile() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"$$"); + + testState.SendReturn(handled: false); + } + + #endregion + + #region generate initial empty raw string + + [WpfFact] + public void TestGenerateAtEndOfFile() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"$$"); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = """"""$$"""""""); + } + + [WpfFact] + public void TestGenerateWithSemicolonAfter() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"$$;"); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = """"""$$"""""";"); + } + + [WpfFact] + public void TestGenerateWithInterpolatedString() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = $""""$$"); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = $""""""$$"""""""); + } + + [WpfFact] + public void TestNoGenerateWithVerbatimString() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = @""""$$"); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = @""""""$$"); + } + + [WpfFact] + public void TestNoGenerateWithVerbatimInterpolatedString1() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = @$""""$$"); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = @$""""""$$"); + } + + [WpfFact] + public void TestNoGenerateWithVerbatimInterpolatedString2() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = $@""""$$"); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = $@""""""$$"); + } + + #endregion + + #region grow empty raw string + + [WpfFact] + public void TestDoNotGrowEmptyInsideSimpleString() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = ""$$"""); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = """"$$"""); + } + + [WpfFact] + public void TestDoNotGrowEmptyInsideFourQuotes() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"$$"""""); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = """"""$$"""""); + } + + [WpfFact] + public void TestDoGrowEmptyInsideSixQuotesInMiddle() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"""$$"""""""); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = """"""""$$"""""""""); + } + + [WpfFact] + public void TestDoGrowEmptyInsideSixQuotesInInterpolatedRaw() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = $""""""$$"""""""); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = $""""""""$$"""""""""); + } + + [WpfFact] + public void TestDoNotGrowEmptyInsideSixQuotesWhenNotInMiddle1() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = $""""$$"""""""""); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = $""""""$$"""""""""); + } + + #endregion + + #region grow delimiters + + [WpfFact] + public void TestGrowDelimetersWhenEndExists_SingleLine() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"""$$ """""""); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = """"""""$$ """""""""); + } + + [WpfFact] + public void TestGrowDelimetersWhenEndExists_MultiLine() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"""$$ + + """""""); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = """"""""$$ + + """""""""); + } + + [WpfFact] + public void TestGrowDelimetersWhenEndExists_Interpolated() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = $""""""$$ + + """""""); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = $""""""""$$ + + """""""""); + } + + [WpfFact] + public void TestDoNotGrowDelimetersWhenEndNotThere() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"""$$"); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = """"""""$$"); + } + + [WpfFact] + public void TestDoNotGrowDelimetersWhenEndTooShort() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"var v = """"""$$ + + """""); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"var v = """"""""$$ + + """""); + } + + #endregion + + [WpfFact] + public void TestTypeQuoteEmptyFile() + { + using var testState = RawStringLiteralTestState.CreateTestState( +@"$$"); + + testState.SendTypeChar('"'); + testState.AssertCodeIs( +@"""$$"); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/RefactoringHelpers/RefactoringHelpersTests.cs b/src/EditorFeatures/CSharpTest/RefactoringHelpers/RefactoringHelpersTests.cs index a583e38874a3f..e065307d0b7d3 100644 --- a/src/EditorFeatures/CSharpTest/RefactoringHelpers/RefactoringHelpersTests.cs +++ b/src/EditorFeatures/CSharpTest/RefactoringHelpers/RefactoringHelpersTests.cs @@ -323,7 +323,26 @@ C LocalFunction(C c) [Fact] [WorkItem(35525, "https://github.com/dotnet/roslyn/issues/35525")] - public async Task TestInEmptySyntaxNode() + public async Task TestInEmptySyntaxNode_AllowEmptyNodesTrue1() + { + var testText = @" +class C +{ + void M() + { + N(0, [||]{|result:|}); + } + + int N(int a, int b, int c) + { + } +}"; + await TestAsync(testText, allowEmptyNodes: true); + } + + [Fact] + [WorkItem(35525, "https://github.com/dotnet/roslyn/issues/35525")] + public async Task TestInEmptySyntaxNode_AllowEmptyNodesTrue2() { var testText = @" class C @@ -337,8 +356,47 @@ int N(int a, int b, int c) { } }"; - await TestAsync(testText); + await TestAsync(testText, allowEmptyNodes: true); + } + + [Fact] + [WorkItem(35525, "https://github.com/dotnet/roslyn/issues/35525")] + public async Task TestInEmptySyntaxNode_AllowEmptyNodesFalse1() + { + var testText = @" +class C +{ + void M() + { + N(0, [||], 0)); + } + + int N(int a, int b, int c) + { + } +}"; + await TestMissingAsync(testText, allowEmptyNodes: false); } + + [Fact] + [WorkItem(35525, "https://github.com/dotnet/roslyn/issues/35525")] + public async Task TestInEmptySyntaxNode_AllowEmptyNodesFalse2() + { + var testText = @" +class C +{ + void M() + { + N(0, {|result:N(0, [||], 0)|}); + } + + int N(int a, int b, int c) + { + } +}"; + await TestAsync(testText, allowEmptyNodes: false); + } + #endregion #region Selections diff --git a/src/EditorFeatures/CSharpTest/RemoveUnnecessaryLambdaExpression/RemoveUnnecessaryLambdaExpressionTests.cs b/src/EditorFeatures/CSharpTest/RemoveUnnecessaryLambdaExpression/RemoveUnnecessaryLambdaExpressionTests.cs new file mode 100644 index 0000000000000..f51e59af519b1 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/RemoveUnnecessaryLambdaExpression/RemoveUnnecessaryLambdaExpressionTests.cs @@ -0,0 +1,1494 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryLambdaExpression; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.RemoveUnnecessaryLambdaExpression +{ + using VerifyCS = CSharpCodeFixVerifier< + CSharpRemoveUnnecessaryLambdaExpressionDiagnosticAnalyzer, + CSharpRemoveUnnecessaryLambdaExpressionCodeFixProvider>; + + public class RemoveUnnecessaryLambdaExpressionTests + { + private static async Task TestInRegularAndScriptAsync(string testCode, string fixedCode, LanguageVersion version = LanguageVersion.Preview) + { + await new VerifyCS.Test + { + TestCode = testCode, + FixedCode = fixedCode, + LanguageVersion = version, + }.RunAsync(); + } + + private static Task TestMissingInRegularAndScriptAsync(string testCode, LanguageVersion version = LanguageVersion.Preview) + => TestInRegularAndScriptAsync(testCode, testCode, version); + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestMissingInCSharp10() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(s => Quux(s)); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}", LanguageVersion.CSharp10); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestBasicCase() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|s => |]Quux(s)); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestWithOptionOff() + { + var code = @"using System; + +class C +{ + void Goo() + { + Bar(s => Quux(s)); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}"; + await new VerifyCS.Test + { + TestCode = code, + FixedCode = code, + LanguageVersion = LanguageVersion.Preview, + Options = { { CSharpCodeStyleOptions.PreferMethodGroupConversion, new CodeStyleOption2(false, NotificationOption2.None) } } + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestNotOnStaticLambda() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(static s => Quux(s)); + } + + void Bar(Func f) { } + static string Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestNotWithOptionalParameter() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(s => Quux(s)); + } + + void Bar(Func f) { } + static string Quux(int i, int j = 0) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestNotWithParams1() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(s => Quux(s)); + } + + void Bar(Func f) { } + static string Quux(int i, params int[] j) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestNotWithParams2() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(s => Quux(s)); + } + + void Bar(Func f) { } + static string Quux(params object[] j) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestWithParams1() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|s => |]Quux(s)); + } + + void Bar(Func f) { } + string Quux(params object[] o) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + string Quux(params object[] o) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestNotWithRefChange1() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(s => Quux(ref s)); + } + + void Bar(Func f) { } + static string Quux(ref int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestNotWithRefChange2() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +delegate string X(ref int i); + +class C +{ + void Goo() + { + Bar((ref int s) => Quux(s)); + } + + void Bar(X x) { } + static string Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestWithSameRef() + { + await TestInRegularAndScriptAsync( +@"using System; + +delegate string X(ref int i); + +class C +{ + void Goo() + { + Bar([|(ref int s) => |]Quux(ref s)); + } + + void Bar(X x) { } + static string Quux(ref int i) => default; +}", + +@"using System; + +delegate string X(ref int i); + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(X x) { } + static string Quux(ref int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestNotOnConversionToObject() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + object o = (int s) => Quux(s); + } + + void Bar(Func f) { } + static string Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestWithParenthesizedLambda() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|(int s) => |]Quux(s)); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestWithAnonymousMethod() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|delegate (int s) { return |]Quux(s); }); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestWithAnonymousMethodNoParameterList() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|delegate { return |]Quux(); }); + } + + void Bar(Func f) { } + string Quux() => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + string Quux() => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestFixCoContravariance1() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|s => |]Quux(s)); + } + + void Bar(Func f) { } + string Quux(object o) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + string Quux(object o) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestFixCoContravariance2() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|s => |]Quux(s)); + } + + void Bar(Func f) { } + string Quux(object o) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + string Quux(object o) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestFixCoContravariance3() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(s => {|CS1662:{|CS0266:Quux(s)|}|}); + } + + void Bar(Func f) { } + object Quux(object o) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestFixCoContravariance4() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(s => Quux({|CS1503:s|})); + } + + void Bar(Func f) { } + string Quux(string o) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestFixCoContravariance5() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(s => Quux({|CS1503:s|})); + } + + void Bar(Func f) { } + object Quux(string o) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestTwoArgs() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|(s1, s2) => |]Quux(s1, s2)); + } + + void Bar(Func f) { } + string Quux(int i, bool b) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + string Quux(int i, bool b) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestMultipleArgIncorrectPassing1() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar((s1, s2) => Quux(s2, s1)); + } + + void Bar(Func f) { } + string Quux(int i, int b) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestMultipleArgIncorrectPassing2() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar((s1, s2) => Quux(s1, s1)); + } + + void Bar(Func f) { } + string Quux(int i, int b) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestMultipleArgIncorrectPassing3() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar((s1, s2) => Quux(s1, true)); + } + + void Bar(Func f) { } + string Quux(int i, bool b) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestReturnStatement() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|(s1, s2) => { + return |]Quux(s1, s2); + }); + } + + void Bar(Func f) { } + string Quux(int i, bool b) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + string Quux(int i, bool b) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestReturnStatement2() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar([|(s1, s2) => { + return |]this.Quux(s1, s2); + }); + } + + void Bar(Func f) { } + string Quux(int i, bool b) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(this.Quux); + } + + void Bar(Func f) { } + string Quux(int i, bool b) => default; +}"); + } + + [WorkItem(542562, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542562")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestMissingOnAmbiguity1() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class A +{ + static void Goo(T x) + { + } + + static void Bar(Action x) + { + } + + static void Bar(Action x) + { + } + + static void Main() + { + {|CS0121:Bar|}(x => Goo(x)); + } +}"); + } + + [WorkItem(542562, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542562")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestWithConstraint1() + { + var code = @" +using System; +class A +{ + static void Goo(T x) where T : class + { + } + + static void Bar(Action x) + { + } + + static void Bar(Action x) + { + } + + static void Main() + { + Bar([|x => |]Goo(x)); + } +}"; + + var expected = @" +using System; +class A +{ + static void Goo(T x) where T : class + { + } + + static void Bar(Action x) + { + } + + static void Bar(Action x) + { + } + + static void Main() + { + Bar(Goo); + } +}"; + await TestInRegularAndScriptAsync(code, expected); + } + + [WorkItem(542562, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542562")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestWithConstraint2() + { + var code = @" +using System; +class A +{ + static void Goo(T x) where T : class + { + } + + static void Bar(Action x) + { + } + + static void Bar(Action x) + { + } + + static void Main() + { + Bar(x => Goo(x)); + } +}"; + await TestMissingInRegularAndScriptAsync(code); + } + + [WorkItem(627092, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/627092")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestMissingOnLambdaWithDynamic_1() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class Program +{ + static void Main() + { + C.InvokeGoo(); + } +} + +class C +{ + public static void InvokeGoo() + { + Action goo = (x, y) => C.Goo(x, y); // Simplify lambda expression + goo(1, """"); + } + + static void Goo(object x, object y) + { + Console.WriteLine(""Goo(object x, object y)""); + } + + static void Goo(object x, T y) + { + Console.WriteLine(""Goo(object x, T y)""); + } +}"); + } + + [WorkItem(627092, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/627092")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestWithLambdaWithDynamic() + { + await TestInRegularAndScriptAsync( +@"using System; + +class Program +{ + static void Main() + { + C.InvokeGoo(); + } +} + +class C +{ + public static void InvokeGoo() + { + Action goo = [|x => |]C.Goo(x); // Simplify lambda expression + goo(1); + } + + private static void Goo(dynamic x) + { + throw new NotImplementedException(); + } + + static void Goo(object x, object y) + { + Console.WriteLine(""Goo(object x, object y)""); + } + + static void Goo(object x, T y) + { + Console.WriteLine(""Goo(object x, T y)""); + } +}", +@"using System; + +class Program +{ + static void Main() + { + C.InvokeGoo(); + } +} + +class C +{ + public static void InvokeGoo() + { + Action goo = C.Goo; // Simplify lambda expression + goo(1); + } + + private static void Goo(dynamic x) + { + throw new NotImplementedException(); + } + + static void Goo(object x, object y) + { + Console.WriteLine(""Goo(object x, object y)""); + } + + static void Goo(object x, T y) + { + Console.WriteLine(""Goo(object x, T y)""); + } +}"); + } + + [WorkItem(544625, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544625")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task ParenthesizeIfParseChanges() + { + var code = @" +using System; +class C +{ + static void M() + { + C x = new C(); + int y = 1; + Bar([|() => { return |]Console.ReadLine(); } < x, y > (1 + 2)); + } + + static void Bar(object a, object b) { } + public static bool operator <(Func y, C x) { return true; } + public static bool operator >(Func y, C x) { return true; } +}"; + + var expected = @" +using System; +class C +{ + static void M() + { + C x = new C(); + int y = 1; + Bar((Console.ReadLine) < x, y > (1 + 2)); + } + + static void Bar(object a, object b) { } + public static bool operator <(Func y, C x) { return true; } + public static bool operator >(Func y, C x) { return true; } +}"; + + await TestInRegularAndScriptAsync(code, expected); + } + + [WorkItem(545856, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545856")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestNotWithSideEffects() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Main() + { + Func a = () => new C().ToString(); + } +}"); + } + + [WorkItem(545994, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545994")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestExpressionStatement() + { + await TestInRegularAndScriptAsync( +@"using System; + +class Program +{ + static void Main() + { + Action a = [|() => { + |]Console.WriteLine(); + }; + } +}", +@"using System; + +class Program +{ + static void Main() + { + Action a = Console.WriteLine; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestTaskOfT1() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|s => |]Quux(s)); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncTaskOfT1() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|async s => await |]Quux(s)); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncTaskOfT2() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|async s => await |]Quux(s).ConfigureAwait(false)); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncNoAwait1() + { + await TestMissingInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(async s => Quux(s)); + } + + void Bar(Func> f) { } + string Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestTaskOfT1_Return() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|s => { return |]Quux(s); }); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncTaskOfT1_Return() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|async s => { return await |]Quux(s); }); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncTaskOfT2_Return() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|async s => { return await |]Quux(s).ConfigureAwait(false); }); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func> f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncNoAwait1_Return() + { + await TestMissingInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(async s => { return Quux(s); }); + } + + void Bar(Func> f) { } + string Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestTask1() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|s => |]Quux(s)); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncTask1() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|async s => await |]Quux(s)); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncTask2() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|async s => await |]Quux(s).ConfigureAwait(false)); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestTask1_ExpressionStatement() + { + await TestMissingInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(s {|CS1643:=>|} { Quux(s); }); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncTask1_ExpressionStatement() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|async s => { await |]Quux(s); }); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncTask2_ExpressionStatement() + { + await TestInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar([|async s => { await |]Quux(s).ConfigureAwait(false); }); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}", +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(Quux); + } + + void Bar(Func f) { } + Task Quux(int i) => default; +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestAsyncNoAwait1_ExpressionStatement() + { + await TestMissingInRegularAndScriptAsync( +@"using System; +using System.Threading.Tasks; + +class C +{ + void Goo() + { + Bar(async s => { Quux(s); }); + } + + void Bar(Func f) { } + void Quux(int i) { } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestExplicitGenericCall() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Action a = [|() => |]Quux(); + } + + void Quux() { } +}", +@"using System; + +class C +{ + void Goo() + { + Action a = Quux; + } + + void Quux() { } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestImplicitGenericCall() + { + await TestMissingInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Action a = b => Quux(b); + } + + void Quux(T t) { } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestNullabilityChanges() + { + await TestMissingInRegularAndScriptAsync( +@" +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +class C +{ + void Goo(List assemblies, HashSet usedProjectFileNames) + { + var projectAssemblyFileNames = Select(assemblies, a => GetFileName(a)); + var v = Any(projectAssemblyFileNames, usedProjectFileNames.Contains); + } + + static List Select(List items, Func map) => new(); + + [return: NotNullIfNotNull(""path"")] + static string? GetFileName(string? path) => path; + + static bool Any(List immutableArray, Func predicate) => true; +} + +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] + public sealed class NotNullIfNotNullAttribute : Attribute + { + public string ParameterName => """"; + + public NotNullIfNotNullAttribute(string parameterName) + { + } + } +} +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryLambdaExpression)] + public async Task TestTrivia1() + { + await TestInRegularAndScriptAsync( +@"using System; + +class C +{ + void Goo() + { + Bar(/*before*/[|s => |]Quux(s)/*after*/); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}", +@"using System; + +class C +{ + void Goo() + { + Bar(/*before*/Quux/*after*/); + } + + void Bar(Func f) { } + string Quux(int i) => default; +}"); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs index b861722304bb1..073d119931052 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs @@ -698,5 +698,72 @@ public C() [|: base((1, (2,$$) |]{} await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); } + + [Theory] + [InlineData("1$$", 0)] + [InlineData(",$$", 1)] + [InlineData(",$$,", 1)] + [InlineData(",,$$", 2)] + [InlineData("i2: 1, $$,", 0)] + [InlineData("i2: 1, i1: $$,", 0)] + [InlineData("i2: 1, $$, i1: 2", 2)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_NamesAndEmptyPositions(string arguments, int expectedParameterIndex) + { + var markup = $@" +class Program +{{ + Program() [|: this({arguments}|]) + {{ + }} + Program(int i1, int i2, int i3) {{ }} +}}"; + + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("Program(int i1, int i2, int i3)", currentParameterIndex: expectedParameterIndex, isSelected: true), + }; + + await TestAsync(markup, expectedOrderedItems); + } + + [Theory] + [InlineData("1$$", 0, 0)] + [InlineData("1$$, ", 0, 0)] + [InlineData("1, $$", 1, 0)] + [InlineData("s: $$", 1, 0)] + [InlineData("s: string.Empty$$", 1, 0)] + [InlineData("s: string.Empty$$, ", 1, 0)] + [InlineData("s: string.Empty, $$", 0, 0)] + [InlineData("string.Empty$$", 0, 1)] + [InlineData("string.Empty$$, ", 0, 1)] + [InlineData("string.Empty,$$", 1, 1)] + [InlineData("$$, ", 0, 0)] + [InlineData(",$$", 1, 0)] + [InlineData("$$, s: string.Empty", 0, 0)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_Incomplete(string arguments, int expectedParameterIndex, int expecteSelectedIndex) + { + var markup = $@" +class Program +{{ + Program() [|: this({arguments}|]) + {{ + }} + Program(int i, string s) {{ }} + Program(string s, string s2) {{ }} +}}"; + + var index = 0; + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("Program(int i, string s)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++), + new SignatureHelpTestItem("Program(string s, string s2)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++), + }; + + await TestAsync(markup, expectedOrderedItems); + } } } diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.cs index df35187528b53..9d76ad4697d39 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.cs @@ -436,10 +436,10 @@ void Test() { Goo($$ } - + void Goo(int a = 42) { } - + }"; var expectedOrderedItems = new List(); @@ -1107,7 +1107,7 @@ void M() public class Goo { [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public static void Bar() + public static void Bar() { } }"; @@ -1139,7 +1139,7 @@ void M() public class Goo { [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public static void Bar() + public static void Bar() { } }"; @@ -1172,7 +1172,7 @@ void M() public class Goo { [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public void Bar() + public void Bar() { } }"; @@ -1213,12 +1213,12 @@ void M() public class Goo { [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Always)] - public void Bar() + public void Bar() { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Bar(int x) + public void Bar(int x) { } }"; @@ -1255,12 +1255,12 @@ void M() public class Goo { [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Bar() + public void Bar() { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Bar(int x) + public void Bar(int x) { } }"; @@ -1292,14 +1292,14 @@ void M() var referencedCode = @" public class B { - public virtual void Goo(int original) + public virtual void Goo(int original) { } } public class D : B { - public override void Goo(int derived) + public override void Goo(int derived) { } }"; @@ -1332,7 +1332,7 @@ void M() [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public class C { - public void Goo() + public void Goo() { } }"; @@ -1364,7 +1364,7 @@ void M() [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public class B { - public void Goo() + public void Goo() { } } @@ -1406,7 +1406,7 @@ void M() public class B { [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Goo() + public void Goo() { } }"; @@ -1533,7 +1533,7 @@ class Program void M() { new C().Goo($$ - + } }"; @@ -1864,7 +1864,7 @@ static void M(string s) { } [Fact, Trait(Traits.Feature, Traits.Features.SignatureHelp)] [WorkItem(25830, "https://github.com/dotnet/roslyn/issues/25830")] - public async Task PickCorrectOverload_FilterFirst_PickIntRemaining() + public async Task PickCorrectOverload_OtherName_PickIntRemaining() { var markup = @" class D @@ -1881,7 +1881,7 @@ static void M(string i) { } var expectedOrderedItems = new List { new SignatureHelpTestItem("void D.M(int i)", currentParameterIndex: 0, isSelected: true), - new SignatureHelpTestItem($"void D.M(string i)", currentParameterIndex: 0), + new SignatureHelpTestItem("void D.M(string i)", currentParameterIndex: 0), }; await TestAsync(markup, expectedOrderedItems); @@ -1889,7 +1889,7 @@ static void M(string i) { } [Fact, Trait(Traits.Feature, Traits.Features.SignatureHelp)] [WorkItem(25830, "https://github.com/dotnet/roslyn/issues/25830")] - public async Task PickCorrectOverload_FilterFirst_PickIntRemaining_ConversionToD() + public async Task PickCorrectOverload_OtherName_PickIntRemaining_ConversionToD() { var markup = @" class D @@ -1907,7 +1907,7 @@ static void M(string i) { } var expectedOrderedItems = new List { new SignatureHelpTestItem("void D.M(int i)", currentParameterIndex: 0, isSelected: true), - new SignatureHelpTestItem($"void D.M(string i)", currentParameterIndex: 0), + new SignatureHelpTestItem("void D.M(string i)", currentParameterIndex: 0), }; await TestAsync(markup, expectedOrderedItems); @@ -1915,7 +1915,7 @@ static void M(string i) { } [Fact, Trait(Traits.Feature, Traits.Features.SignatureHelp)] [WorkItem(25830, "https://github.com/dotnet/roslyn/issues/25830")] - public async Task PickCorrectOverload_FilterFirst_PickIntRemaining_ReversedOrder() + public async Task PickCorrectOverload_OtherName_PickIntRemaining_ReversedOrder() { var markup = @" class D @@ -1932,7 +1932,7 @@ static void M(D filtered) { } var expectedOrderedItems = new List { new SignatureHelpTestItem("void D.M(int i)", currentParameterIndex: 0, isSelected: true), - new SignatureHelpTestItem($"void D.M(string i)", currentParameterIndex: 0), + new SignatureHelpTestItem("void D.M(string i)", currentParameterIndex: 0), }; await TestAsync(markup, expectedOrderedItems); @@ -1940,7 +1940,7 @@ static void M(D filtered) { } [Fact, Trait(Traits.Feature, Traits.Features.SignatureHelp)] [WorkItem(25830, "https://github.com/dotnet/roslyn/issues/25830")] - public async Task PickCorrectOverload_FilterFirst_PickStringRemaining() + public async Task PickCorrectOverload_OtherName_PickStringRemaining() { var markup = @" class D @@ -1957,12 +1957,272 @@ static void M(string i) { } var expectedOrderedItems = new List { new SignatureHelpTestItem("void D.M(int i)", currentParameterIndex: 0), - new SignatureHelpTestItem($"void D.M(string i)", currentParameterIndex: 0, isSelected: true), + new SignatureHelpTestItem("void D.M(string i)", currentParameterIndex: 0, isSelected: true), + }; + + await TestAsync(markup, expectedOrderedItems); + } + + [Fact, Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(25830, "https://github.com/dotnet/roslyn/issues/25830")] + public async Task PickCorrectOverload_RefKind() + { + var markup = @" +class D +{ + static void Main() + { + int i = 0; + [|M(out i$$|]); + } + static void M(ref int a, int i) { } + static void M(out int b, int i) { } +}"; + + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("void D.M(ref int a, int i)", currentParameterIndex: 0), + new SignatureHelpTestItem("void D.M(out int b, int i)", currentParameterIndex: 0, isSelected: true), + }; + + await TestAsync(markup, expectedOrderedItems); + } + + [Theory] + [InlineData("1$$", 0)] + [InlineData(",$$", 1)] + [InlineData(",$$,", 1)] + [InlineData(",,$$", 2)] + [InlineData("i2: 1, $$,", 0)] + [InlineData("i2: 1, i1: $$,", 0)] + [InlineData("i2: 1, $$, i1: 2", 2)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_NamesAndEmptyPositions(string arguments, int expectedParameterIndex) + { + var markup = @" +class Program +{ + static void Main() + { + [|M(ARGUMENTS|]); + } + static void M(int i1, int i2, int i3) { } +}"; + + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("void Program.M(int i1, int i2, int i3)", currentParameterIndex: expectedParameterIndex, isSelected: true), + }; + + await TestAsync(markup.Replace("ARGUMENTS", arguments), expectedOrderedItems); + } + + [Theory] + [InlineData("1$$", 0)] + [InlineData(",$$", 1)] + [InlineData(",$$,", 1)] + [InlineData(",,$$", 2)] + [InlineData("i2: 1, $$,", 0)] + [InlineData("i2: 1, i1: $$,", 0)] + [InlineData("i2: 1, $$, i1: 2", 2)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_NamesAndEmptyPositions_Delegate(string arguments, int expectedParameterIndex) + { + var markup = @" +class Program +{ + delegate void Delegate(int i1, int i2, int i3); + void Main(Delegate d) + { + [|d(ARGUMENTS|]); + } +}"; + + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("void Delegate(int i1, int i2, int i3)", currentParameterIndex: expectedParameterIndex, isSelected: true), + }; + + await TestAsync(markup.Replace("ARGUMENTS", arguments), expectedOrderedItems); + } + + [Theory] + [InlineData("1$$", 0, 0)] + [InlineData("1$$, ", 0, 0)] + [InlineData("1, $$", 1, 0)] + [InlineData("s: $$", 1, 0)] + [InlineData("s: string.Empty$$", 1, 0)] + [InlineData("s: string.Empty$$, ", 1, 0)] + [InlineData("s: string.Empty, $$", 0, 0)] + [InlineData("string.Empty$$", 0, 1)] + [InlineData("string.Empty$$, ", 0, 1)] + [InlineData("string.Empty,$$", 1, 1)] + [InlineData("$$, ", 0, 0)] + [InlineData(",$$", 1, 0)] + [InlineData("$$, s: string.Empty", 0, 0)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_Incomplete(string arguments, int expectedParameterIndex, int expecteSelectedIndex) + { + var markup = @" +class Program +{ + static void Main() + { + [|M(ARGUMENTS|]); + } + static void M(int i, string s) { } + static void M(string s, string s2) { } +}"; + + var index = 0; + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("void Program.M(int i, string s)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++), + new SignatureHelpTestItem("void Program.M(string s, string s2)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++), + }; + + await TestAsync(markup.Replace("ARGUMENTS", arguments), expectedOrderedItems); + } + + [Theory] + [InlineData("s2: $$", 1)] + [InlineData("s2: string.Empty$$", 1)] + [InlineData("s2: string.Empty$$,", 1)] + [InlineData("s2: string.Empty,$$", 0)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_Incomplete_WithNames(string arguments, int expectedParameterIndex) + { + var markup = @" +class Program +{ + static void Main() + { + [|M(ARGUMENTS|]); + } + static void M(int i, string s) { } + static void M(string s, string s2) { } +}"; + + var expectedOrderedItems = new List + { + new SignatureHelpTestItem($"void Program.M(string s, string s2)", currentParameterIndex: expectedParameterIndex, isSelected: true), + }; + + await TestAsync(markup.Replace("ARGUMENTS", arguments), expectedOrderedItems); + } + + [Theory] + [InlineData("1$$", 0)] + [InlineData("1$$,", 0)] + [InlineData("1$$, 2", 0)] + [InlineData("1, $$", 1)] + [InlineData("1, 2$$", 1)] + [InlineData("1, 2$$, ", 1)] + [InlineData("1, 2$$, 3", 1)] + [InlineData("1, 2, 3$$", 1)] + [InlineData("1, , 3$$", 1)] + [InlineData(" , , 3$$", 1)] + [InlineData("i1: 1, 2, 3$$", 1)] + [InlineData("i1: 1$$, i2: new int[] { }", 0)] + [InlineData("i2: new int[] { }$$, i1: 1", 1)] + [InlineData("i1: 1, i2: new int[] { }$$", 1)] + [InlineData("i2: new int[] { }, i1: 1$$", 0)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_Params(string arguments, int expectedParameterIndex) + { + var markup = @" +class Program +{ + void Main() + { + [|M(ARGUMENTS|]); + } + void M(int i1, params int[] i2) { } +}"; + + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("void Program.M(int i1, params int[] i2)", currentParameterIndex: expectedParameterIndex, isSelected: true), + }; + + await TestAsync(markup.Replace("ARGUMENTS", arguments), expectedOrderedItems); + } + + [Fact] + public async Task PickCorrectOverload_Params_NonArrayType() + { + var source = @" +class Program +{ + void Main() + { + [|M(1, 2$$|]); + } + void M(int i1, params int i2) { } +}"; + + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("void Program.M(int i1, params int i2)", currentParameterIndex: 1, isSelected: true), + }; + + await TestAsync(source, expectedOrderedItems); + } + + [Fact] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_Incomplete_OutOfPositionArgument() + { + var markup = @" +class Program +{ + static void Main() + { + [|M(string.Empty, s3: string.Empty, $$|]); + } + static void M(string s1, string s2, string s3) { } +}"; + // The first unspecified parameter (s2) is selected + var expectedOrderedItems = new List + { + new SignatureHelpTestItem($"void Program.M(string s1, string s2, string s3)", currentParameterIndex: 1, isSelected: true), }; await TestAsync(markup, expectedOrderedItems); } + [Theory] + [InlineData("i: 1", 0)] + [InlineData("i: 1, ", 1)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_IncompleteWithNameI(string arguments, int expectedParameterIndex) + { + var markup = @" +class Program +{ + static void Main() + { + [|M(ARGUMENTS$$|]); + } + static void M(int i, string s) { } + static void M(string s, string s2) { } +}"; + + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("void Program.M(int i, string s)", currentParameterIndex: expectedParameterIndex, isSelected: true), + }; + + await TestAsync(markup.Replace("ARGUMENTS", arguments), expectedOrderedItems); + } + [Fact, Trait(Traits.Feature, Traits.Features.SignatureHelp)] public async Task TestInvocationWithCrefXmlComments() { @@ -2059,7 +2319,7 @@ public async Task InstanceAndStaticMethodsShown1() class C { Goo Goo; - + void M() { Goo.Bar($$ @@ -2089,7 +2349,7 @@ public async Task InstanceAndStaticMethodsShown2() class C { Goo Goo; - + void M() { Goo.Bar($$""); @@ -2119,7 +2379,7 @@ public async Task InstanceAndStaticMethodsShown3() class C { Goo Goo; - + void M() { Goo.Bar($$ diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs index b37274f468661..2505fc893fed6 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs @@ -784,5 +784,72 @@ public C M() await TestAsync(markup, expectedOrderedItems, usePreviousCharAsTrigger: true); } + + [Theory] + [InlineData("1$$", 0, 0)] + [InlineData("1$$, ", 0, 0)] + [InlineData("1, $$", 1, 0)] + [InlineData("s: $$", 1, 0)] + [InlineData("s: string.Empty$$", 1, 0)] + [InlineData("s: string.Empty$$, ", 1, 0)] + [InlineData("s: string.Empty, $$", 0, 0)] + [InlineData("string.Empty$$", 0, 1)] + [InlineData("string.Empty$$, ", 0, 1)] + [InlineData("string.Empty,$$", 1, 1)] + [InlineData("$$, ", 0, 0)] + [InlineData(",$$", 1, 0)] + [InlineData("$$, s: string.Empty", 0, 0)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_Incomplete(string arguments, int expectedParameterIndex, int expecteSelectedIndex) + { + var markup = @" +class Program +{ + static void M() + { + [|new Program(ARGUMENTS|]); + } + Program(int i, string s) { } + Program(string s, string s2) { } +}"; + + var index = 0; + var expectedOrderedItems = new List + { + new SignatureHelpTestItem("Program(int i, string s)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++), + new SignatureHelpTestItem("Program(string s, string s2)", currentParameterIndex: expectedParameterIndex, isSelected: expecteSelectedIndex == index++), + }; + + await TestAsync(markup.Replace("ARGUMENTS", arguments), expectedOrderedItems); + } + + [Theory] + [InlineData("s2: $$", 1)] + [InlineData("s2: string.Empty$$", 1)] + [InlineData("s2: string.Empty$$,", 1)] + [InlineData("s2: string.Empty,$$", 0)] + [Trait(Traits.Feature, Traits.Features.SignatureHelp)] + [WorkItem(6713, "https://github.com/dotnet/roslyn/issues/6713")] + public async Task PickCorrectOverload_Incomplete_WithNames(string arguments, int expectedParameterIndex) + { + var markup = @" +class Program +{ + void M() + { + [|new Program(ARGUMENTS|]); + } + Program(int i, string s) { } + Program(string s, string s2) { } +}"; + + var expectedOrderedItems = new List + { + new SignatureHelpTestItem($"Program(string s, string s2)", currentParameterIndex: expectedParameterIndex, isSelected: true), + }; + + await TestAsync(markup.Replace("ARGUMENTS", arguments), expectedOrderedItems); + } } } diff --git a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs index d384a56e89863..c44723ac7b064 100644 --- a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs @@ -49,7 +49,7 @@ private static void TestWorker( // TODO: set SmartIndent to textView.Options (https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1412138) workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options - .WithChangedOption(FormattingBehaviorOptions.SmartIndent, LanguageNames.CSharp, indentStyle))); + .WithChangedOption(AutoFormattingOptions.Metadata.SmartIndent, LanguageNames.CSharp, indentStyle))); if (useTabs && expectedOutputMarkup != null) { @@ -900,5 +900,50 @@ void M() }", useTabs: true); } + + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingInRawStringLiteral() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = """"""Hello[||]there +world +""""""; + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingInRawStringLiteralInterpolation() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = $""""""Hello[||]there +world +""""""; + } +}"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.SplitStringLiteral)] + public void TestMissingInRawStringLiteralInterpolation_MultiBrace() + { + TestNotHandled( +@"class C +{ + void M() + { + var v = ${|#0:|}$""""""Hello[||]there +world +""""""; + } +}"); + } } } diff --git a/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs b/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs new file mode 100644 index 0000000000000..f898c87f65d74 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs @@ -0,0 +1,660 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.StringIndentation; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringIndentation +{ + [UseExportProvider] + public class StringIndentationTests + { + private static async Task TestAsync(string contents) + { + using var workspace = TestWorkspace.CreateWorkspace( + TestWorkspace.CreateWorkspaceElement(LanguageNames.CSharp, + files: new[] { contents.Replace("|", " ") }, + isMarkup: false)); + var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id); + var root = await document.GetRequiredSyntaxRootAsync(default); + + var service = document.GetRequiredLanguageService(); + var regions = await service.GetStringIndentationRegionsAsync(document, root.FullSpan, CancellationToken.None).ConfigureAwait(false); + + var actual = ApplyRegions(contents.Replace("|", " "), regions); + Assert.Equal(contents, actual); + } + + private static string ApplyRegions(string val, ImmutableArray regions) + { + var text = SourceText.From(val); + using var _ = ArrayBuilder.GetInstance(out var changes); + + foreach (var region in regions) + { + var firstLine = text.Lines.GetLineFromPosition(region.IndentSpan.Start); + var lastLine = text.Lines.GetLineFromPosition(region.IndentSpan.End); + var offset = region.IndentSpan.End - lastLine.Start; + + for (var i = firstLine.LineNumber + 1; i < lastLine.LineNumber; i++) + { + var lineStart = text.Lines[i].Start; + if (region.OrderedHoleSpans.Any(s => s.Contains(lineStart))) + continue; + + changes.Add(new TextChange(new TextSpan(lineStart + offset - 1, 1), "|")); + } + } + + var changedText = text.WithChanges(changes); + return changedText.ToString(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestEmptyFile() + => await TestAsync(string.Empty); + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestLiteralError1() + { + await TestAsync(@"class C +{ + void M() + { + // not enough lines in literal + var v = """""" + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestLiteralError2() + { + await TestAsync(@"class C +{ + void M() + { + // invalid literal + var v = """""" + text too early + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestZeroColumn1() + { + await TestAsync(@"class C +{ + void M() + { + var v = """""" +goo +""""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestZeroColumn2() + { + await TestAsync(@"class C +{ + void M() + { + var v = """""" + goo +""""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestOneColumn1() + { + await TestAsync(@"class C +{ + void M() + { + var v = """""" +|goo + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestOneColumn2() + { + await TestAsync(@"class C +{ + void M() + { + var v = """""" +| goo + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase1() + { + await TestAsync(@"class C +{ + void M() + { + var v = """""" + |goo + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase2() + { + await TestAsync(@"class C +{ + void M() + { + var v = """""" + |goo + |bar + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase3() + { + await TestAsync(@"class C +{ + void M() + { + var v = """""" + |goo + |bar + |baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase4() + { + await TestAsync(@"class C +{ + void M() + { + var v = """""" + |goo + | + |baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase5() + { + await TestAsync(@"class C +{ + void M() + { + var v = """""" + | goo + | + | baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase6() + { + await TestAsync(@"class C +{ + void M() + { + var v = + $"""""" + |goo + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase7() + { + await TestAsync(@"class C +{ + void M() + { + var v = + $"""""" + |goo + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase8() + { + await TestAsync(@"class C +{ + void M() + { + var v = + $"""""""" + |goo + """"""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase9() + { + await TestAsync(@"class C +{ + void M() + { + var v = + """""""" + |goo + """"""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase10() + { + await TestAsync(@"class C +{ + void M() + { + var v = + $$"""""""" + |goo + """"""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase11() + { + await TestAsync(@"class C +{ + void M() + { + var v = + $$"""""""" + |goo + """"""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestCase12() + { + await TestAsync(@"class C +{ + void M() + { + var v = + $$"""""""" + |goo + """"""""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles1() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + | goo + | { 1 + 1 } + | baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles2() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + | goo{ + | 1 + 1 + | }baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles3() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + | goo{ + |1 + 1 + | }baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles4() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + | goo{ + 1 + 1 + }baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles5() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + | goo{ + |1 + 1 + | }baz + | quux + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles6() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + | goo{ + 1 + 1 + }baz + | quux + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles7() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + |goo{ + 1 + 1 + }baz + |quux + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles8() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + | { 1 + 1 } + | baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles9() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + | { + | 1 + 1 + | } + | baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithHoles10() + { + await TestAsync(@"class C +{ + void M() + { + var v = $"""""" + | { + 1 + 1 + } + | baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithNestedHoles1() + { + await TestAsync(@"class C +{ + void M() + { + var x = + $"""""" + |goo + |{ + | $"""""" + | |bar + | """""" + |} + |baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithNestedHoles2() + { + await TestAsync(@"class C +{ + void M() + { + var x = + $"""""" + |goo + |{ + | $"""""" + | |bar + | |{ + | | 1 + 1 + | |} + | """""" + |} + |baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithNestedHoles3() + { + await TestAsync(@"class C +{ + void M() + { + var x = + $"""""" + |goo + |{ + | $"""""" + | |bar + | |{ + | 1 + 1 + | } + | """""" + |} + |baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithNestedHoles4() + { + await TestAsync(@"class C +{ + void M() + { + var x = + $"""""" + |goo + |{ + $"""""" + |bar + |{ + 1 + 1 + } + """""" + } + |baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithNestedHoles5() + { + await TestAsync(@"class C +{ + void M() + { + var x = + $"""""" + |goo + |{ + $"""""" + |bar + """""" + } + |baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithNestedHoles6() + { + await TestAsync(@"class C +{ + void M() + { + var x = + $"""""" + |goo + |{ + $"""""" + |bar + |{ + | 1 + 1 + |} + """""" + } + |baz + """"""; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.StringIndentation)] + public async Task TestWithNestedHoles7() + { + await TestAsync(@"class C +{ + void M() + { + var x = + $"""""" + |goo + |{ + $"""""" + |bar + |{ + 1 + 1 + } + """""" + } + |baz + """"""; + } +}"); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs index 04c006bb5d3bf..38d3b172a24be 100644 --- a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs +++ b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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.CodeStyle; @@ -223,5 +221,26 @@ void Goo() } }", parameters: new TestParameters(options: UseBlockBody)); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + [WorkItem(53532, "https://github.com/dotnet/roslyn/issues/53532")] + public async Task TestTriviaOnArrow1() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M() + // Test + [||]=> Console.WriteLine(); +}", +@"class C +{ + void M() + { + // Test + Console.WriteLine(); + } +}", parameters: new TestParameters(options: UseExpressionBody)); + } } } diff --git a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs index cf4a26490a9f3..d67eccd9c6172 100644 --- a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs +++ b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs @@ -1211,16 +1211,16 @@ public void TestSolutionWithOptions() var optionValue = solution.Options.GetOption(optionKey); Assert.Equal(BackgroundAnalysisScope.Default, optionValue); - var newOptions = solution.Options.WithChangedOption(optionKey, BackgroundAnalysisScope.ActiveFile); + var newOptions = solution.Options.WithChangedOption(optionKey, BackgroundAnalysisScope.FullSolution); var newSolution = solution.WithOptions(newOptions); var newOptionValue = newSolution.Options.GetOption(optionKey); - Assert.Equal(BackgroundAnalysisScope.ActiveFile, newOptionValue); + Assert.Equal(BackgroundAnalysisScope.FullSolution, newOptionValue); var applied = workspace.TryApplyChanges(newSolution); Assert.True(applied); var currentOptionValue = workspace.CurrentSolution.Options.GetOption(optionKey); - Assert.Equal(BackgroundAnalysisScope.ActiveFile, currentOptionValue); + Assert.Equal(BackgroundAnalysisScope.FullSolution, currentOptionValue); } [CombinatorialData] @@ -1253,12 +1253,12 @@ public void TestOptionChangedHandlerInvokedAfterCurrentSolutionChanged(bool test if (testDeprecatedOptionsSetter) { #pragma warning disable CS0618 // Type or member is obsolete - this test ensures that deprecated "Workspace.set_Options" API's functionality is preserved. - primaryWorkspace.Options = primaryWorkspace.Options.WithChangedOption(optionKey, BackgroundAnalysisScope.ActiveFile); + primaryWorkspace.Options = primaryWorkspace.Options.WithChangedOption(optionKey, BackgroundAnalysisScope.FullSolution); #pragma warning restore CS0618 // Type or member is obsolete } else { - primaryWorkspace.SetOptions(primaryWorkspace.Options.WithChangedOption(optionKey, BackgroundAnalysisScope.ActiveFile)); + primaryWorkspace.SetOptions(primaryWorkspace.Options.WithChangedOption(optionKey, BackgroundAnalysisScope.FullSolution)); } // Verify current solution and option change for both workspaces. @@ -1284,7 +1284,7 @@ static void VerifyCurrentSolutionAndOptionChange(Workspace workspace, Solution b // Verify workspace.CurrentSolution has changed option. var optionKey = new OptionKey2(SolutionCrawlerOptions.BackgroundAnalysisScopeOption, LanguageNames.CSharp); Assert.Equal(BackgroundAnalysisScope.Default, beforeOptionChangedSolution.Options.GetOption(optionKey)); - Assert.Equal(BackgroundAnalysisScope.ActiveFile, currentSolution.Options.GetOption(optionKey)); + Assert.Equal(BackgroundAnalysisScope.FullSolution, currentSolution.Options.GetOption(optionKey)); } } } diff --git a/src/EditorFeatures/CSharpTest/Wrapping/AbstractWrappingTests.cs b/src/EditorFeatures/CSharpTest/Wrapping/AbstractWrappingTests.cs index 1e80695915cf5..99210d479517f 100644 --- a/src/EditorFeatures/CSharpTest/Wrapping/AbstractWrappingTests.cs +++ b/src/EditorFeatures/CSharpTest/Wrapping/AbstractWrappingTests.cs @@ -21,7 +21,7 @@ protected sealed override ImmutableArray MassageActions(ImmutableArr private protected OptionsCollection GetIndentionColumn(int column) => new OptionsCollection(GetLanguage()) { - { FormattingBehaviorOptions.PreferredWrappingColumn, column } + { FormattingOptions2.PreferredWrappingColumn, column } }; protected Task TestAllWrappingCasesAsync( diff --git a/src/EditorFeatures/CSharpTest/Wrapping/InitializerExpressionWrappingTests.cs b/src/EditorFeatures/CSharpTest/Wrapping/InitializerExpressionWrappingTests.cs new file mode 100644 index 0000000000000..c7fa1ae9105cb --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Wrapping/InitializerExpressionWrappingTests.cs @@ -0,0 +1,535 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.Wrapping; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Wrapping +{ + public class IntializerExpressionWrappingTests : AbstractWrappingTests + { + protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) + => new CSharpWrappingCodeRefactoringProvider(); + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestNoWrappingSuggestions() + { + await TestMissingAsync( +@"class C { + void Bar() { + var test = new[] [||]{ 1 }; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestWrappingShortInitializerExpression() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + var test = new[] [||]{ 1, 2 }; + } +}", +@"class C { + void Bar() { + var test = new[] + { + 1, + 2 + }; + } +}", +@"class C { + void Bar() { + var test = new[] + { + 1, 2 + }; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestWrappingLongIntializerExpression() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + var test = new[] [||]{ ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"" }; + } +}", +@"class C { + void Bar() { + var test = new[] + { + ""the"", + ""quick"", + ""brown"", + ""fox"", + ""jumps"", + ""over"", + ""the"", + ""lazy"", + ""dog"" + }; + } +}", +@"class C { + void Bar() { + var test = new[] + { + ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"" + }; + } +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestWrappingMultiLineLongIntializerExpression() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + var test = new[] [||]{ ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"", ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"" }; + } +}", +@"class C { + void Bar() { + var test = new[] + { + ""the"", + ""quick"", + ""brown"", + ""fox"", + ""jumps"", + ""over"", + ""the"", + ""lazy"", + ""dog"", + ""the"", + ""quick"", + ""brown"", + ""fox"", + ""jumps"", + ""over"", + ""the"", + ""lazy"", + ""dog"" + }; + } +}", +@"class C { + void Bar() { + var test = new[] + { + ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"", ""the"", ""quick"", ""brown"", ""fox"", + ""jumps"", ""over"", ""the"", ""lazy"", ""dog"" + }; + } +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestShortInitializerExpressionRefactorings() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + var test = new[] + [||]{ + 1, + 2 + }; + } +}", +@"class C { + void Bar() { + var test = new[] { 1, 2 }; + } +}", +@"class C { + void Bar() { + var test = new[] + { + 1, 2 + }; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestLongIntializerExpressionRefactorings() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + var test = new[] + [||]{ + ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"" + }; + } +}", +@"class C { + void Bar() { + var test = new[] + { + ""the"", + ""quick"", + ""brown"", + ""fox"", + ""jumps"", + ""over"", + ""the"", + ""lazy"", + ""dog"" + }; + } +}", +@"class C { + void Bar() { + var test = new[] { ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"" }; + } +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestListWrappingIntializerExpression() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + var test = new List [||]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + } +}", +@"class C { + void Bar() { + var test = new List + { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }; + } +}", +@"class C { + void Bar() { + var test = new List + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; + } +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestWrappedListIntializerExpression() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + var test = new List + [||]{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }; + } +}", +@"class C { + void Bar() { + var test = new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + } +}", +@"class C { + void Bar() { + var test = new List + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; + } +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestObjectWrappingIntializerExpression() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + var test = new List [||]{ new A { B = 1, C = 1 }, new A { B = 2, C = 2 }, new A { B = 3, C = 3 } }; + } +}", +@"class C { + void Bar() { + var test = new List + { + new A { B = 1, C = 1 }, + new A { B = 2, C = 2 }, + new A { B = 3, C = 3 } + }; + } +}", +@"class C { + void Bar() { + var test = new List + { + new A { B = 1, C = 1 }, new A { B = 2, C = 2 }, new A { B = 3, C = 3 } + }; + } +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestWrappedObjectIntializerExpression() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + var test = new List + [||]{ + new A { B = 1, C = 1 }, + new A { B = 2, C = 2 }, + new A { B = 3, C = 3 } + }; + } +}", +@"class C { + void Bar() { + var test = new List { new A { B = 1, C = 1 }, new A { B = 2, C = 2 }, new A { B = 3, C = 3 } }; + } +}", +@"class C { + void Bar() { + var test = new List + { + new A { B = 1, C = 1 }, new A { B = 2, C = 2 }, new A { B = 3, C = 3 } + }; + } +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestReturnIntializerExpression() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + return new List [||]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + } +}", +@"class C { + void Bar() { + return new List + { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }; + } +}", +@"class C { + void Bar() { + return new List + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; + } +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestWrappedReturnIntializerExpression() + { + await TestAllWrappingCasesAsync( +@"class C { + void Bar() { + return new List + [||]{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }; + } +}", +@"class C { + void Bar() { + return new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + } +}", +@"class C { + void Bar() { + return new List + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; + } +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestClassPropertyIntializerExpressionRefactorings() + { + await TestAllWrappingCasesAsync( +@"public class C { + public List B => new List [||]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; +}", +@"public class C { + public List B => new List + { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }; +}", +@"public class C { + public List B => new List + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestWrappedClassPropertyIntializerExpressionRefactorings() + { + await TestAllWrappingCasesAsync( +@"public class C { + public List B => new List + [||]{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }; +}", +@"public class C { + public List B => new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; +}", +@"public class C { + public List B => new List + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestArgumentIntializerExpressionRefactorings() + { + await TestAllWrappingCasesAsync( +@"public void F() { + var result = fakefunction(new List [||]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); +}", +@"public void F() { + var result = fakefunction(new List + { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }); +}", +@"public void F() { + var result = fakefunction(new List + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }); +}" +); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + public async Task TestWrappedArgumentIntializerExpressionRefactorings() + { + await TestAllWrappingCasesAsync( +@"public void F() { + var result = fakefunction(new List + [||]{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }); +}", +@"public void F() { + var result = fakefunction(new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); +}", +@"public void F() { + var result = fakefunction(new List + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }); +}" +); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/Wrapping/ParameterWrappingTests.cs b/src/EditorFeatures/CSharpTest/Wrapping/ParameterWrappingTests.cs index e6f1d1c514d27..d20d0c72cdbe2 100644 --- a/src/EditorFeatures/CSharpTest/Wrapping/ParameterWrappingTests.cs +++ b/src/EditorFeatures/CSharpTest/Wrapping/ParameterWrappingTests.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.Wrapping; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Wrapping @@ -810,6 +811,22 @@ public C(int i, }"); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] + [WorkItem(38986, "https://github.com/dotnet/roslyn/issues/38986")] + public async Task TestInConstructorWithSyntaxErrorAfter() + { + await TestInRegularAndScript1Async( +@"class C { + public [||]C(int i, int j) : base(,) { + } +}", +@"class C { + public C(int i, + int j) : base(,) { + } +}"); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] public async Task TestInIndexer() { diff --git a/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_BasicTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_BasicTests.cs new file mode 100644 index 0000000000000..84db8de6c6532 --- /dev/null +++ b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_BasicTests.cs @@ -0,0 +1,5934 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.EmbeddedLanguages.Json +{ + public partial class CSharpJsonParserBasicTests : CSharpJsonParserTests + { + [Fact] + public void TestEmpty() + { + Test(@"""""", expected: null, + @"", + @"", runLooseSubTreeCheck: false); + } + + [Fact] + public void TestOneSpace() + { + Test(@""" """, @" + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestTwoSpaces() + { + Test(@""" """, @" + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestTabSpace() + { + Test(@"""\t""", @" + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestFormFeed() + { + Test(@"""\f""", @" + + + + + \f + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestFormFeed2() + { + Test(@"""[\f1,0]""", @" + + + + [\f + + + 1 + + + , + + + 0 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestFormFeed3() + { + // .net strict parsers don't report the problem with the trailing \f. we do as it's + // per the ecma spec. + Test(@"""[0\f,1]""", @" + + + + [ + + + 0\f + + + , + + + 1 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestSingleLineComment() + { + Test(@"""//""", @" + + + + + // + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestSingleLineCommentWithContent() + { + Test(@"""// """, @" + + + + + // + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestEmptyMultiLineComment() + { + Test(@"""/**/""", @" + + + + + /**/ + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestMultiLineCommentWithStar() + { + Test(@"""/***/""", @" + + + + + /***/ + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestArray1() + { + Test(@"""[]""", @" + + + + [ + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void TestArray2() + { + Test(@""" [ ] """, @" + + + + + + + [ + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void TestArray3() + { + Test(@"""[""", @" + + + + [ + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestArray4() + { + Test(@"""]""", @" + + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestArray5() + { + Test(@"""[,]""", @" + + + + [ + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestArray6() + { + Test(@"""[true,]""", @" + + + + [ + + + true + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestArray7() + { + Test(@"""[true]""", @" + + + + [ + + + true + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void TestArray8() + { + Test(@"""[,,]""", @" + + + + [ + + + , + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestArray9() + { + Test(@"""[true,,]""", @" + + + + [ + + + true + + + , + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestArray10() + { + Test(@"""[,true,]""", @" + + + + [ + + + , + + + true + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestArray11() + { + Test(@"""[,,true]""", @" + + + + [ + + + , + + + , + + + true + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestTrueLiteral1() + { + Test(@"""true""", @" + + + + true + + + + +", + @"", + @""); + } + + [Fact] + public void TestTrueLiteral2() + { + Test(@""" true """, @" + + + + + + + true + + + + +", + @"", + @""); + } + + [Fact] + public void TestFalseLiteral1() + { + Test(@"""false""", @" + + + + false + + + + +", + @"", + @""); + } + + [Fact] + public void TestFalseLiteral2() + { + Test(@""" false """, @" + + + + + + + false + + + + +", + @"", + @""); + } + + [Fact] + public void TestNullLiteral1() + { + Test(@"""null""", @" + + + + null + + + + +", + @"", + @""); + } + + [Fact] + public void TestNullLiteral2() + { + Test(@""" null """, @" + + + + + + + null + + + + +", + @"", + @""); + } + + [Fact] + public void TestUndefinedLiteral1() + { + Test(@"""undefined""", @" + + + + undefined + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNaNLiteral1() + { + Test(@"""NaN""", @" + + + + NaN + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNaNLiteral2() + { + Test(@""" NaN """, @" + + + + + + + NaN + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNaNLiteral3() + { + Test(@"""nan""", @" + + + + nan + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestInfinity1() + { + Test(@"""Infinity""", @" + + + + Infinity + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNegativeInfinity1() + { + Test(@"""-Infinity""", @" + + + + - + Infinity + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNegativeInfinity2() + { + Test(@"""- Infinity""", @" + + + + - + + + Infinity + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestArrayWithMissingCommas() + { + Test(@"""[0 1 2]""", @" + + + + [ + + + 0 + + + 1 + + + 2 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestIncompleteNull1() + { + Test(@"""n""", @" + + + + n + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestIncompleteNull2() + { + Test(@"""nu""", @" + + + + nu + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestIncompleteUnicode1() + { + Test(@"@""'h\u123'""", @" + + + + 'h\u123' + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestIncompleteEscape() + { + Test(@"@""'h\u'""", @" + + + + 'h\u' + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestIncompleteUnicode2() + { + Test(@"@""""""h\u123""""""", @" + + + + ""h\u123"" + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestIncompleteEscape2() + { + Test(@"@""""""h\u""""""", @" + + + + ""h\u"" + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestInvalidNonBase10() + { + Test(@"""0aq2dun13.hod""", @" + + + + 0aq2dun13.hod + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestUnterminatedString() + { + Test(@"""'hi""", @" + + + + 'hi + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestUnterminatedString2() + { + Test(@"""\""hi""", @" + + + + ""hi + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestExtraEndToken() + { + Test(@"""{}}""", @" + + + + { + + } + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestMultiObject1() + { + Test(@"""{'first':1,'second':2,'third':3}""", @" + + + + { + + + 'first' + : + + 1 + + + , + + 'second' + : + + 2 + + + , + + 'third' + : + + 3 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestMultiObject2() + { + Test(@"""{\""first\"":1,\""second\"":2,\""third\"":3}""", @" + + + + { + + + ""first"" + : + + 1 + + + , + + ""second"" + : + + 2 + + + , + + ""third"" + : + + 3 + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void TestExtraChar() + { + Test(@"""nullz""", @" + + + + nullz + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestMissingColon() + { + Test(@"@""{ 'a': 0, 'b' 0 }""", @" + + + + { + + + 'a' + : + + 0 + + + , + + 'b' + + + + 0 + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNestedPropertyMissingColon() + { + Test(@"@"" +{ + """"description"""": """"A person"""", + """"type"""": """"object"""", + """"properties"""": + { + """"name"""" {""""type"""":""""string""""}, + """"hobbies"""": { + """"type"""": """"array"""", + """"items"""": {""""type"""":""""string""""} + } + } +}""", @" + + + + + + + + { + + + + + + + ""description"" + : + + ""A person"" + + + , + + + + + + ""type"" + : + + ""object"" + + + , + + + + + + ""properties"" + : + + + + + + { + + + + + + + ""name"" + + + + { + + + ""type"" + : + + ""string"" + + + + } + + , + + + + + + ""hobbies"" + : + + { + + + + + + + ""type"" + : + + ""array"" + + + , + + + + + + ""items"" + : + + { + + + ""type"" + : + + ""string"" + + + + } + + + + + + + + } + + + + + + + + } + + + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestMissingColon2() + { + Test(@"@""{ """"a"""": 0, """"b"""" 0 }""", @" + + + + { + + + ""a"" + : + + 0 + + + , + + ""b"" + + + + 0 + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestAdditionalContentComma() + { + Test(@"@""[ +""""Small"""", +""""Medium"""", +""""Large"""" +],""", @" + + + + [ + + + + ""Small"" + + + , + + + + ""Medium"" + + + , + + + + ""Large"" + + + + ] + + + , + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestAdditionalContentText() + { + Test(@"@""[ +""""Small"""", +""""Medium"""", +""""Large"""" +]content""", @" + + + + [ + + + + ""Small"" + + + , + + + + ""Medium"" + + + , + + + + ""Large"" + + + + ] + + + content + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestAdditionalContentWhitespaceText() + { + Test(@"@""'hi' a""", @" + + + + 'hi' + + + a + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestAdditionalContentWhitespaceText2() + { + Test(@"@""""""hi"""" a""", @" + + + + ""hi"" + + + a + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestTrailingCommentStart() + { + Test(@"@""true/""", @" + + + + true/ + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestBadCharInArray() + { + Test(@"@""[}""", @" + + + + [ + + + } + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestIncompleteObject() + { + Test(@"@""{""", @" + + + + { + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestEmptyObject() + { + Test(@"@""{}""", @" + + + + { + + } + + + + +", + @"", + @""); + } + + [Fact] + public void TestLargeInt() + { + Test(@"@""3333333333333333333333333333333333333""", @" + + + + 3333333333333333333333333333333333333 + + + + +", + @"", + @""); + } + + [Fact] + public void TestIdentifierProperty() + { + Test(@"@""{ a: 0 }""", @" + + + + { + + + a + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNumericProperty() + { + Test(@"@""{ 1: 0 }""", @" + + + + { + + + 1 + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNegativeNumericProperty() + { + Test(@"@""{ -1: 0 }""", @" + + + + { + + + -1 + : + + 0 + + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestArrayPropertyName() + { + Test(@"@""{ []: 0 }""", @" + + + + { + + + [ + + ] + + + + : + + + + 0 + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNaNPropertyName() + { + Test(@"@""{ NaN: 0 }""", @" + + + + { + + + NaN + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestInfinityPropertyName() + { + Test(@"@""{ Infinity: 0 }""", @" + + + + { + + + Infinity + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNullPropertyName() + { + Test(@"@""{ null: 0 }""", @" + + + + { + + + null + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestUndefinedPropertyName() + { + Test(@"@""{ undefined: 0 }""", @" + + + + { + + + undefined + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNameWithSpace() + { + Test(@"@""{ a b : 0 }""", @" + + + + { + + + a + + + + b + : + + 0 + + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNameWithNumber() + { + Test(@"@""{ a0 : 0 }""", @" + + + + { + + + a0 + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNumberWithHexName() + { + Test(@"@""{ 0a : 0 }""", @" + + + + { + + + 0a + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNumberWithNonHexName() + { + Test(@"@""{ 0z : 0 }""", @" + + + + { + + + 0z + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestDollarPropName() + { + Test(@"@""{ $ : 0 }""", @" + + + + { + + + $ + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestUnderscorePropName() + { + Test(@"@""{ _ : 0 }""", @" + + + + { + + + _ + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestStrangeLegalPropName() + { + Test(@"@""{ 0$0 : 0 }""", @" + + + + { + + + 0$0 + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestStrangeIllegalPropName() + { + Test(@"@""{ 0(0 : 0 }""", @" + + + + { + + + 0 + + + + ( + + + + 0 + : + + 0 + + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestStrangeIllegalPropName2() + { + Test(@"@""{ 0%0 : 0 }""", @" + + + + { + + + 0%0 + : + + 0 + + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestObjectWithEmptyPropValue1() + { + Test(@"""{'first': , }""", @" + + + + { + + + 'first' + : + + + + + , + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestObjectWithEmptyPropValue2() + { + Test(@"""{\""first\"": , }""", @" + + + + { + + + ""first"" + : + + + + + , + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestObjectWithEmptyPropValue3() + { + Test(@"""{'first': }""", @" + + + + { + + + 'first' + : + + } + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestObjectWithEmptyPropValue4() + { + Test(@"""{\""first\"": }""", @" + + + + { + + + ""first"" + : + + } + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestObjectWithEmptyPropValue5() + { + Test(@"""{'first': """, @" + + + + { + + + 'first' + : + + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestObjectWithEmptyPropValue6() + { + Test(@"""{\""first\"": """, @" + + + + { + + + ""first"" + : + + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNestedProp1() + { + Test(@"""{'first': 'second': 'third' }""", @" + + + + { + + + 'first' + : + + 'second' + : + + 'third' + + + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNestedProp2() + { + Test(@"""{\""first\"": \""second\"": \""third\"" }""", @" + + + + { + + + ""first"" + : + + ""second"" + : + + ""third"" + + + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestMultiItemList() + { + Test(@"""[{ 'name': 'Admin' },{ 'name': 'Publisher' },1,null,[],,'string']""", @" + + + + [ + + + { + + + 'name' + : + + 'Admin' + + + + } + + + , + + + { + + + 'name' + : + + 'Publisher' + + + + } + + + , + + + 1 + + + , + + + null + + + , + + + [ + + ] + + + , + + + , + + + 'string' + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestMultiItemList2() + { + Test(@"""[{ \""name\"": \""Admin\"" },{ \""name\"": \""Publisher\"" },1,null,[],,\""string\""]""", @" + + + + [ + + + { + + + ""name"" + : + + ""Admin"" + + + + } + + + , + + + { + + + ""name"" + : + + ""Publisher"" + + + + } + + + , + + + 1 + + + , + + + null + + + , + + + [ + + ] + + + , + + + , + + + ""string"" + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestMultiLine1() + { + Test(@"@"" +{'a': +'bc','d':true +}""", @" + + + + + + + + { + + + 'a' + : + + + 'bc' + + + , + + 'd' + : + + true + + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestMultiLine2() + { + Test(@"@"" +{""""a"""": +""""bc"""",""""d"""":true +}""", @" + + + + + + + + { + + + ""a"" + : + + + ""bc"" + + + , + + ""d"" + : + + true + + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void TestNestedObject() + { + Test(@"@"" +{ + 'description': 'A person', + 'type': 'object', + 'properties': + { + 'name': {'type':'string'}, + 'hobbies': { + 'type': 'array', + 'items': {'type':'string'} + } + } +}""", @" + + + + + + + + { + + + + + + + 'description' + : + + 'A person' + + + , + + + + + + 'type' + : + + 'object' + + + , + + + + + + 'properties' + : + + + + + + { + + + + + + + 'name' + : + + { + + + 'type' + : + + 'string' + + + + } + + + , + + + + + + 'hobbies' + : + + { + + + + + + + 'type' + : + + 'array' + + + , + + + + + + 'items' + : + + { + + + 'type' + : + + 'string' + + + + } + + + + + + + + } + + + + + + + + } + + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNestedObject1() + { + Test(@"@"" +{ + """"description"""": """"A person"""", + """"type"""": """"object"""", + """"properties"""": + { + """"name"""": {""""type"""":""""string""""}, + """"hobbies"""": { + """"type"""": """"array"""", + """"items"""": {""""type"""":""""string""""} + } + } +}""", @" + + + + + + + + { + + + + + + + ""description"" + : + + ""A person"" + + + , + + + + + + ""type"" + : + + ""object"" + + + , + + + + + + ""properties"" + : + + + + + + { + + + + + + + ""name"" + : + + { + + + ""type"" + : + + ""string"" + + + + } + + + , + + + + + + ""hobbies"" + : + + { + + + + + + + ""type"" + : + + ""array"" + + + , + + + + + + ""items"" + : + + { + + + ""type"" + : + + ""string"" + + + + } + + + + + + + + } + + + + + + + + } + + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void TestLiterals1() + { + Test(@"@""{ A: '', B: 1, C: , D: 1.23, E: 3.45, F: null }""", @" + + + + { + + + A + : + + '' + + + , + + B + : + + 1 + + + , + + C + : + + + + + , + + D + : + + 1.23 + + + , + + E + : + + 3.45 + + + , + + F + : + + null + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestLiterals2() + { + Test(@"@""{ """"A"""": """""""", """"B"""": 1, """"D"""": 1.23, """"E"""": 3.45, """"F"""": null }""", @" + + + + { + + + ""A"" + : + + """" + + + , + + ""B"" + : + + 1 + + + , + + ""D"" + : + + 1.23 + + + , + + ""E"" + : + + 3.45 + + + , + + ""F"" + : + + null + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void TestLiterals3() + { + Test(@"@""[ + 1, + 0, + 1.1, + 0.0, + 0.000000000001, + 9999999999, + -9999999999, + 9999999999999999999999999999999999999999999999999999999999999999999999, + -9999999999999999999999999999999999999999999999999999999999999999999999, + 'true', + 'TRUE', + 'false', + 'FALSE', + // comment! + /* comment! */ + '', + null +]""", @" + + + + [ + + + + + + + 1 + + + , + + + + + + + 0 + + + , + + + + + + + 1.1 + + + , + + + + + + + 0.0 + + + , + + + + + + + 0.000000000001 + + + , + + + + + + + 9999999999 + + + , + + + + + + + -9999999999 + + + , + + + + + + + 9999999999999999999999999999999999999999999999999999999999999999999999 + + + , + + + + + + + -9999999999999999999999999999999999999999999999999999999999999999999999 + + + , + + + + + + + 'true' + + + , + + + + + + + 'TRUE' + + + , + + + + + + + 'false' + + + , + + + + + + + 'FALSE' + + + , + + + + + + + // comment! + + + + /* comment! */ + + + + '' + + + , + + + + + + + null + + + + ] + + + + +", + @"", + @" + +", runLooseSubTreeCheck: false); + } + + [Fact] + public void TestCommentsInArray() + { + Test(@"@""[/*hi*/1/*hi*/,2/*hi*/]""", @" + + + + [/*hi*/ + + + 1/*hi*/ + + + , + + + 2/*hi*/ + + + ] + + + + +", + @"", + @" + +", runLooseSubTreeCheck: false); + } + + [Fact] + public void TestUnicode2() + { + Test(@"@""{'text':0xabcdef12345}""", @" + + + + { + + + 'text' + : + + 0xabcdef12345 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestUnicode3() + { + Test(@"@""{""""text"""":0xabcdef12345}""", @" + + + + { + + + ""text"" + : + + 0xabcdef12345 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestOctal1() + { + Test(@"@""[0372, 0xFA, 0XFA]""", @" + + + + [ + + + 0372 + + + , + + + 0xFA + + + , + + + 0XFA + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestObjectLiteralComments() + { + Test(@"@""/*comment*/ { /*comment*/ + 'Name': /*comment*/ 'Apple' /*comment*/, /*comment*/ + 'ExpiryDate': '1', + 'Price': 3.99, + 'Sizes': /*comment*/ [ /*comment*/ + 'Small', /*comment*/ + 'Medium' /*comment*/, + /*comment*/ 'Large' + /*comment*/ ] /*comment*/ + } /*comment*/""", @" + + + + + + /*comment*/ + + { /*comment*/ + + + + + + + 'Name' + : /*comment*/ + + 'Apple' /*comment*/ + + + , /*comment*/ + + + + + + 'ExpiryDate' + : + + '1' + + + , + + + + + + 'Price' + : + + 3.99 + + + , + + + + + + 'Sizes' + : /*comment*/ + + [ /*comment*/ + + + + + + + 'Small' + + + , /*comment*/ + + + + + + + 'Medium' /*comment*/ + + + , + + + + + + + /*comment*/ + + 'Large' + + + + + + + /*comment*/ + + ] /*comment*/ + + + + + + + + } /*comment*/ + + + + +", + @"", + @" + +", runLooseSubTreeCheck: false); + } + + [Fact] + public void TestEmptyStrings() + { + Test(@"@""['','','','','','','']""", @" + + + + [ + + + '' + + + , + + + '' + + + , + + + '' + + + , + + + '' + + + , + + + '' + + + , + + + '' + + + , + + + '' + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestEmptyStrings2() + { + Test(@"@""["""""""","""""""","""""""","""""""","""""""","""""""",""""""""]""", @" + + + + [ + + + """" + + + , + + + """" + + + , + + + """" + + + , + + + """" + + + , + + + """" + + + , + + + """" + + + , + + + """" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void TestInvalidNumber() + { + Test(@"@""0-10""", @" + + + + 0-10 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestSimpleEscapes() + { + Test(@"@""[false, true, true, false, 'test!', 1.11, 0e-10, 0E-10, 0.25e-5, 0.3e10, 6.0221418e23, 'Purple\r \n monkey\'s:\tdishwasher']""", @" + + + + [ + + + false + + + , + + + true + + + , + + + true + + + , + + + false + + + , + + + 'test!' + + + , + + + 1.11 + + + , + + + 0e-10 + + + , + + + 0E-10 + + + , + + + 0.25e-5 + + + , + + + 0.3e10 + + + , + + + 6.0221418e23 + + + , + + + 'Purple\r \n monkey\'s:\tdishwasher' + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestSimpleEscapes2() + { + Test(@"@""[false, true, true, false, """"test!"""", 1.11, 0e-10, 0E-10, 0.25e-5, 0.3e10, 6.0221418e23, """"Purple\r \n monkey\'s:\tdishwasher""""]""", @" + + + + [ + + + false + + + , + + + true + + + , + + + true + + + , + + + false + + + , + + + ""test!"" + + + , + + + 1.11 + + + , + + + 0e-10 + + + , + + + 0E-10 + + + , + + + 0.25e-5 + + + , + + + 0.3e10 + + + , + + + 6.0221418e23 + + + , + + + ""Purple\r \n monkey\'s:\tdishwasher"" + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestDoubleQuoteInSingleQuote() + { + Test(@"@""'a""""b'""", @" + + + + 'a""b' + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestMultiLineString() + { + Test(@"@""'a +b'""", @" + + + + 'a +b' + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestMultiLineString2() + { + Test(@"@""""""a +b""""""", @" + + + + ""a +b"" + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor1() + { + Test(@"@""new""", @" + + + + new + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestConstructor2() + { + Test(@"@""new A""", @" + + + + new + A + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestConstructor3() + { + Test(@"@""new A(""", @" + + + + new + A + ( + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestConstructor4() + { + Test(@"@""new A()""", @" + + + + new + A + ( + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor5() + { + Test(@"@""new A(1)""", @" + + + + new + A + ( + + + 1 + + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor6() + { + Test(@"@""new A(1, 2)""", @" + + + + new + A + ( + + + 1 + + + , + + + 2 + + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor7() + { + Test(@"@""new A([new B()])""", @" + + + + new + A + ( + + + [ + + + new + B + ( + + ) + + + ] + + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor8() + { + Test(@"@""new A(,)""", @" + + + + new + A + ( + + + , + + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor9() + { + Test(@"@""new A(1,)""", @" + + + + new + A + ( + + + 1 + + + , + + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor10() + { + Test(@"@""new A(,1)""", @" + + + + new + A + ( + + + , + + + 1 + + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor11() + { + Test(@"@""new A(1,1)""", @" + + + + new + A + ( + + + 1 + + + , + + + 1 + + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor12() + { + Test(@"@""new A(1,,1)""", @" + + + + new + A + ( + + + 1 + + + , + + + , + + + 1 + + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestConstructor13() + { + Test(@"@""new %()""", @" + + + + new + % + ( + + ) + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestConstructor14() + { + Test(@"@""new A(1 2)""", @" + + + + new + A + ( + + + 1 + + + 2 + + + ) + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestMultipleCommasInObject() + { + Test(@"@""{0:0,,1:1}""", @" + + + + { + + + 0 + : + + 0 + + + , + + , + + + + 1 + : + + 1 + + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestSimpleEscapes3() + { + Test(@"@"" """"\r\n\f\t\b"""" """, @" + + + + + + + ""\r\n\f\t\b"" + + + + +", + @"", + @""); + } + + [Fact] + public void TestSimpleEscapes4() + { + Test(@"@"" """"\m"""" """, @" + + + + + + + ""\m"" + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestSimpleEscapes5() + { + Test(@"@"" """"\\\/\"""""""" """, @" + + + + + + + ""\\\/\"""" + + + + +", + @"", + @""); + } + + [Fact] + public void TestSimpleEscapes6() + { + Test(@"@"" """"\'"""" """, @" + + + + + + + ""\'"" + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestSimpleEscapes7() + { + Test(@"@"" '\'' """, @" + + + + + + + '\'' + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestSimpleEscapes8() + { + Test(@"@"" '\""""' """, @" + + + + + + + '\""' + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestPropertyInArray1() + { + Test(@"@"" [""""a"""": 0] """, @" + + + + + + + [ + + + ""a"" + : + + 0 + + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestSimpleNumber1() + { + Test(@"@""0.0""", @" + + + + 0.0 + + + + +", + @"", + @""); + } + + [Fact] + public void TestSimpleNumber2() + { + Test(@"@""-0.0""", @" + + + + -0.0 + + + + +", + @"", + @""); + } + + [Fact] + public void TestSimpleNumber3() + { + Test(@"@"".0""", @" + + + + .0 + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestSimpleNumber4() + { + Test(@"@""-.0""", @" + + + + -.0 + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestStandaloneMinus() + { + Test(@"@""-""", @" + + + + - + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestMinusDot() + { + Test(@"@""-.""", @" + + + + -. + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber1() + { + Test(@"@""0""", @" + + + + 0 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber2() + { + Test(@"@""-0""", @" + + + + -0 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber3() + { + Test(@"@""00""", @" + + + + 00 + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNumber4() + { + Test(@"@""-00""", @" + + + + -00 + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNumber5() + { + Test(@"@""0.""", @" + + + + 0. + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNumber6() + { + Test(@"@""-0.""", @" + + + + -0. + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestNumber7() + { + Test(@"@""0e""", @" + + + + 0e + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber8() + { + Test(@"@""-0e""", @" + + + + -0e + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber9() + { + Test(@"@""0e0""", @" + + + + 0e0 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber10() + { + Test(@"@""-0e0""", @" + + + + -0e0 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber11() + { + Test(@"@""0e1""", @" + + + + 0e1 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber12() + { + Test(@"@""-0e1""", @" + + + + -0e1 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber13() + { + Test(@"@""0e-1""", @" + + + + 0e-1 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber14() + { + Test(@"@""-0e-1""", @" + + + + -0e-1 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber15() + { + Test(@"@""0e+1""", @" + + + + 0e+1 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber16() + { + Test(@"@""-0e+1""", @" + + + + -0e+1 + + + + +", + @"", + @""); + } + + [Fact] + public void TestNumber17() + { + Test(@"@""--0""", @" + + + + --0 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber18() + { + Test(@"@""+0""", @" + + + + +0 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber19() + { + Test(@"@""0..0""", @" + + + + 0..0 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber20() + { + Test(@"@""0ee0""", @" + + + + 0ee0 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber21() + { + Test(@"@""1e++1""", @" + + + + 1e++1 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber22() + { + Test(@"@""1e--1""", @" + + + + 1e--1 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber23() + { + Test(@"@""1e+-1""", @" + + + + 1e+-1 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber24() + { + Test(@"@""1e-+1""", @" + + + + 1e-+1 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber25() + { + Test(@"@""1e1.0""", @" + + + + 1e1.0 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber26() + { + Test(@"@""1e+1.1""", @" + + + + 1e+1.1 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber27() + { + Test(@"@""1-1""", @" + + + + 1-1 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNumber28() + { + Test(@"@""1+1""", @" + + + + 1+1 + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestIncompleteProperty() + { + Test(@"""{ 'a': }""", @" + + + + { + + + 'a' + : + + } + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestPropertyWithCommaFollowedByComma() + { + Test(@"""{ 'a': , , }""", @" + + + + { + + + 'a' + : + + + + + , + + , + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestTopLevelProperty() + { + Test(@"""'a': 0""", @" + + + + 'a' + : + + 0 + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestTopLevelConstructor() + { + Test(@"""new Date()""", @" + + + + new + Date + ( + + ) + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestTopLevelText() + { + Test(@"""Date""", @" + + + + Date + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestNestedArrays1() + { + Test(@"""[1, [2, [3, [4]]]]""", @" + + + + [ + + + 1 + + + , + + + [ + + + 2 + + + , + + + [ + + + 3 + + + , + + + [ + + + 4 + + + ] + + + ] + + + ] + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void TestNestedArraysTrailingCommas1() + { + Test(@"""[1, [2, [3, [4,],],],]""", @" + + + + [ + + + 1 + + + , + + + [ + + + 2 + + + , + + + [ + + + 3 + + + , + + + [ + + + 4 + + + , + + + ] + + + , + + + ] + + + , + + + ] + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestBogusNesting1() + { + Test(@"""[1, [2, [3, [4}}}}""", @" + + + + [ + + + 1 + + + , + + + [ + + + 2 + + + , + + + [ + + + 3 + + + , + + + [ + + + 4 + + + } + + + } + + + } + + + } + + + + + + + + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestBogusNesting2() + { + Test(@"""[1, [2, [3, [4}]}]""", @" + + + + [ + + + 1 + + + , + + + [ + + + 2 + + + , + + + [ + + + 3 + + + , + + + [ + + + 4 + + + } + + + ] + + + } + + + ] + + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestBogusNesting3() + { + Test(@"""{1, {2, {3, {4]]]]""", @" + + + + { + + + 1 + + , + + { + + + 2 + + , + + { + + + 3 + + , + + { + + + 4 + + + + ] + + + + ] + + + + ] + + + + ] + + + + + + + + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestBogusNesting4() + { + Test(@"""[1, {2, [3, {4]]]]""", @" + + + + [ + + + 1 + + + , + + + { + + + 2 + + , + + [ + + + 3 + + + , + + + { + + + 4 + + + + + + ] + + + + + + ] + + + ] + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestBogusNesting5() + { + Test(@"""[1, {2, [3, {4]}]}""", @" + + + + [ + + + 1 + + + , + + + { + + + 2 + + , + + [ + + + 3 + + + , + + + { + + + 4 + + + + + + ] + + + } + + + ] + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestBogusNesting6() + { + Test(@"""[1, {2, [3, {4}]}]""", @" + + + + [ + + + 1 + + + , + + + { + + + 2 + + , + + [ + + + 3 + + + , + + + { + + + 4 + + + } + + + ] + + + } + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void TestIntegerPropertyName() + { + Test(@"""{ 0: true }""", expected: @" + + + + { + + + 0 + : + + true + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void TestColonPropertyName() + { + Test(@"""{ :: true }""", expected: @" + + + + { + + + : + : + + true + + + + } + + + + +", + @" + +", + @" + +"); + } + } +} diff --git a/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_NstTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_NstTests.cs new file mode 100644 index 0000000000000..579cc5e8eb4b9 --- /dev/null +++ b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_NstTests.cs @@ -0,0 +1,7972 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// tests from: https://github.com/nst/JSONTestSuite +using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.EmbeddedLanguages.Json +{ + public partial class CSharpJsonParserNstTests : CSharpJsonParserTests + { + private void TestNST( + string stringText, string expected, string _, string strictDiagnostics, [CallerMemberName] string caller = "") + { + var (_, tree, allChars) = JustParseTree(stringText, JsonOptions.Strict, conversionFailureOk: false); + Assert.NotNull(tree); + Roslyn.Utilities.Contract.ThrowIfNull(tree); + var actualTree = TreeToText(tree!).Replace("\"", "\"\""); + Assert.Equal(expected.Replace("\"", "\"\""), actualTree); + + var actualDiagnostics = DiagnosticsToText(tree.Diagnostics).Replace("\"", "\"\""); + Assert.Equal(strictDiagnostics.Replace("\"", "\"\""), actualDiagnostics); + + CheckInvariants(tree, allChars); + + if (caller.StartsWith("y_")) + { + // y_ tests must produce no diagnostics. + Assert.Empty(strictDiagnostics); + } + else if (caller.StartsWith("i_")) + { + // We don't want to have diagnostics for i_ tests even though we're allowed to. + // That's because we want our parser to be permissive when possible so we don't + // error on json that is legal under some other parser. + Assert.Empty(strictDiagnostics); + } + else if (caller.StartsWith("n_")) + { + // n_ tests must always produce diagnostics. + Assert.NotEmpty(strictDiagnostics); + } + else + { + Assert.False(true, "Unexpected test name."); + } + } + + [Fact] + public void i_number_double_huge_neg_exp_json() + { + TestNST(@"@""[123.456e-789]""", @" + + + + [ + + + 123.456e-789 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_number_huge_exp_json() + { + TestNST(@"@""[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006]""", @" + + + + [ + + + 0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006 + + + ] + + + + +", + @" + +", + @""); + } + + [Fact] + public void i_number_neg_int_huge_exp_json() + { + TestNST(@"@""[-1e+9999]""", @" + + + + [ + + + -1e+9999 + + + ] + + + + +", + @" + +", + @""); + } + + [Fact] + public void i_number_pos_double_huge_exp_json() + { + TestNST(@"@""[1.5e+9999]""", @" + + + + [ + + + 1.5e+9999 + + + ] + + + + +", + @" + +", + @""); + } + + [Fact] + public void i_number_real_neg_overflow_json() + { + TestNST(@"@""[-123123e100000]""", @" + + + + [ + + + -123123e100000 + + + ] + + + + +", + @" + +", + @""); + } + + [Fact] + public void i_number_real_pos_overflow_json() + { + TestNST(@"@""[123123e100000]""", @" + + + + [ + + + 123123e100000 + + + ] + + + + +", + @" + +", + @""); + } + + [Fact] + public void i_number_real_underflow_json() + { + TestNST(@"@""[123e-10000000]""", @" + + + + [ + + + 123e-10000000 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_number_too_big_neg_int_json() + { + TestNST(@"@""[-123123123123123123123123123123]""", @" + + + + [ + + + -123123123123123123123123123123 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_number_too_big_pos_int_json() + { + TestNST(@"@""[100000000000000000000]""", @" + + + + [ + + + 100000000000000000000 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_number_very_big_negative_int_json() + { + TestNST(@"@""[-237462374673276894279832749832423479823246327846]""", @" + + + + [ + + + -237462374673276894279832749832423479823246327846 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_object_key_lone_2nd_surrogate_json() + { + TestNST(@"@""{""""\uDFAA"""":0}""", @" + + + + { + + + ""\uDFAA"" + : + + 0 + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_1st_surrogate_but_2nd_missing_json() + { + TestNST(@"@""[""""\uDADA""""]""", @" + + + + [ + + + ""\uDADA"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_1st_valid_surrogate_2nd_invalid_json() + { + TestNST(@"@""[""""\uD888\u1234""""]""", @" + + + + [ + + + ""\uD888\u1234"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_incomplete_surrogates_escape_valid_json() + { + TestNST(@"@""[""""\uD800\uD800\n""""]""", @" + + + + [ + + + ""\uD800\uD800\n"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_incomplete_surrogate_and_escape_valid_json() + { + TestNST(@"@""[""""\uD800\n""""]""", @" + + + + [ + + + ""\uD800\n"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_incomplete_surrogate_pair_json() + { + TestNST(@"@""[""""\uDd1ea""""]""", @" + + + + [ + + + ""\uDd1ea"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_invalid_lonely_surrogate_json() + { + TestNST(@"@""[""""\ud800""""]""", @" + + + + [ + + + ""\ud800"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_invalid_surrogate_json() + { + TestNST(@"@""[""""\ud800abc""""]""", @" + + + + [ + + + ""\ud800abc"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_invalid_utf_8_json() + { + TestNST(@"@""[""""�""""]""", @" + + + + [ + + + ""�"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_inverted_surrogates_U_1D11E_json() + { + TestNST(@"@""[""""\uDd1e\uD834""""]""", @" + + + + [ + + + ""\uDd1e\uD834"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_iso_latin_1_json() + { + TestNST(@"@""[""""�""""]""", @" + + + + [ + + + ""�"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_lone_second_surrogate_json() + { + TestNST(@"@""[""""\uDFAA""""]""", @" + + + + [ + + + ""\uDFAA"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_lone_utf8_continuation_byte_json() + { + TestNST(@"@""[""""�""""]""", @" + + + + [ + + + ""�"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_not_in_unicode_range_json() + { + TestNST(@"@""[""""���""""]""", @" + + + + [ + + + ""���"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_overlong_sequence_2_bytes_json() + { + TestNST(@"@""[""""��""""]""", @" + + + + [ + + + ""��"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_overlong_sequence_6_bytes_json() + { + TestNST(@"@""[""""������""""]""", @" + + + + [ + + + ""������"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_overlong_sequence_6_bytes_null_json() + { + TestNST(@"@""[""""������""""]""", @" + + + + [ + + + ""������"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_truncated_utf_8_json() + { + TestNST(@"@""[""""��""""]""", @" + + + + [ + + + ""��"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_UTF_16LE_with_BOM_json() + { + TestNST(@"@""[""""é""""]""", @" + + + + [ + + + ""é"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_UTF_8_invalid_sequence_json() + { + TestNST(@"@""[""""日ш�""""]""", @" + + + + [ + + + ""日ш�"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_string_UTF8_surrogate_U_D800_json() + { + TestNST(@"@""[""""��""""]""", @" + + + + [ + + + ""��"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void i_structure_UTF_8_BOM_empty_object_json() + { + TestNST(@"@""{}""", @" + + + + { + + } + + + + +", + @"", + @""); + } + + [Fact] + public void n_array_1_true_without_comma_json() + { + TestNST(@"@""[1 true]""", @" + + + + [ + + + 1 + + + true + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_a_invalid_utf8_json() + { + TestNST(@"@""[a�]""", @" + + + + [ + + + a� + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_colon_instead_of_comma_json() + { + TestNST(@"@""["""""""": 1]""", @" + + + + [ + + + """" + : + + 1 + + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_comma_after_close_json() + { + TestNST(@"@""[""""""""],""", @" + + + + [ + + + """" + + + ] + + + , + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_comma_and_number_json() + { + TestNST(@"@""[,1]""", @" + + + + [ + + + , + + + 1 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_array_double_comma_json() + { + TestNST(@"@""[1,,2]""", @" + + + + [ + + + 1 + + + , + + + , + + + 2 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_array_double_extra_comma_json() + { + TestNST(@"@""[""""x"""",,]""", @" + + + + [ + + + ""x"" + + + , + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_array_extra_close_json() + { + TestNST(@"@""[""""x""""]]""", @" + + + + [ + + + ""x"" + + + ] + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_extra_comma_json() + { + TestNST(@"@""["""""""",]""", @" + + + + [ + + + """" + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_array_incomplete_json() + { + TestNST(@"@""[""""x""""""", @" + + + + [ + + + ""x"" + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_incomplete_invalid_value_json() + { + TestNST(@"@""[x""", @" + + + + [ + + + x + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_inner_array_no_comma_json() + { + TestNST(@"@""[3[4]]""", @" + + + + [ + + + 3 + + + [ + + + 4 + + + ] + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_invalid_utf8_json() + { + TestNST(@"@""[�]""", @" + + + + [ + + + + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_items_separated_by_semicolon_json() + { + TestNST(@"@""[1:2]""", @" + + + + [ + + + 1 + : + + 2 + + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_just_comma_json() + { + TestNST(@"@""[,]""", @" + + + + [ + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_array_just_minus_json() + { + TestNST(@"@""[-]""", @" + + + + [ + + + - + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_missing_value_json() + { + TestNST(@"@""[ , """"""""]""", @" + + + + [ + + + , + + + """" + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_array_newlines_unclosed_json() + { + TestNST(@"@""[""""a"""", +4 +,1,""", @" + + + + [ + + + ""a"" + + + , + + + + 4 + + + + , + + + 1 + + + , + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_number_and_comma_json() + { + TestNST(@"@""[1,]""", @" + + + + [ + + + 1 + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_array_number_and_several_commas_json() + { + TestNST(@"@""[1,,]""", @" + + + + [ + + + 1 + + + , + + + , + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_array_star_inside_json() + { + TestNST(@"@""[*]""", @" + + + + [ + + + * + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_unclosed_json() + { + TestNST(@"@""[""""""""""", @" + + + + [ + + + """" + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_unclosed_trailing_comma_json() + { + TestNST(@"@""[1,""", @" + + + + [ + + + 1 + + + , + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_unclosed_with_new_lines_json() + { + TestNST(@"@""[1, +1 +,1""", @" + + + + [ + + + 1 + + + , + + + + 1 + + + + , + + + 1 + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_array_unclosed_with_object_inside_json() + { + TestNST(@"@""[{}""", @" + + + + [ + + + { + + } + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_incomplete_false_json() + { + TestNST(@"@""[fals]""", @" + + + + [ + + + fals + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_incomplete_null_json() + { + TestNST(@"@""[nul]""", @" + + + + [ + + + nul + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_incomplete_true_json() + { + TestNST(@"@""[tru]""", @" + + + + [ + + + tru + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number____json() + { + TestNST(@"@""[++1234]""", @" + + + + [ + + + ++1234 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number__1_json() + { + TestNST(@"@""[+1]""", @" + + + + [ + + + +1 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number__Inf_json() + { + TestNST(@"@""[+Inf]""", @" + + + + [ + + + +Inf + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number__01_json() + { + TestNST(@"@""[-01]""", @" + + + + [ + + + -01 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number__1_0__json() + { + TestNST(@"@""[-1.0.]""", @" + + + + [ + + + -1.0. + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number__2__json() + { + TestNST(@"@""[-2.]""", @" + + + + [ + + + -2. + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number__NaN_json() + { + TestNST(@"@""[-NaN]""", @" + + + + [ + + + -NaN + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number___1_json() + { + TestNST(@"@""[.-1]""", @" + + + + [ + + + .-1 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number__2e_3_json() + { + TestNST(@"@""[.2e-3]""", @" + + + + [ + + + .2e-3 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_0_1_2_json() + { + TestNST(@"@""[0.1.2]""", @" + + + + [ + + + 0.1.2 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_0_3e__json() + { + TestNST(@"@""[0.3e+]""", @" + + + + [ + + + 0.3e+ + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_0_3e_json() + { + TestNST(@"@""[0.3e]""", @" + + + + [ + + + 0.3e + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_0_e1_json() + { + TestNST(@"@""[0.e1]""", @" + + + + [ + + + 0.e1 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_0e__json() + { + TestNST(@"@""[0e+]""", @" + + + + [ + + + 0e+ + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_0e_json() + { + TestNST(@"@""[0e]""", @" + + + + [ + + + 0e + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_0_capital_E__json() + { + TestNST(@"@""[0E+]""", @" + + + + [ + + + 0E+ + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_0_capital_E_json() + { + TestNST(@"@""[0E]""", @" + + + + [ + + + 0E + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_1_0e__json() + { + TestNST(@"@""[1.0e+]""", @" + + + + [ + + + 1.0e+ + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_1_0e_json() + { + TestNST(@"@""[1.0e]""", @" + + + + [ + + + 1.0e + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_1eE2_json() + { + TestNST(@"@""[1eE2]""", @" + + + + [ + + + 1eE2 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_1_000_json() + { + TestNST(@"@""[1 000.0]""", @" + + + + [ + + + 1 + + + 000.0 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_2_e_3_json() + { + TestNST(@"@""[2.e+3]""", @" + + + + [ + + + 2.e+3 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_2_e3_json() + { + TestNST(@"@""[2.e3]""", @" + + + + [ + + + 2.e3 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_9_e__json() + { + TestNST(@"@""[9.e+]""", @" + + + + [ + + + 9.e+ + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_expression_json() + { + TestNST(@"@""[1+2]""", @" + + + + [ + + + 1+2 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_hex_1_digit_json() + { + TestNST(@"@""[0x1]""", @" + + + + [ + + + 0x1 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_hex_2_digits_json() + { + TestNST(@"@""[0x42]""", @" + + + + [ + + + 0x42 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_Inf_json() + { + TestNST(@"@""[Inf]""", @" + + + + [ + + + Inf + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_infinity_json() + { + TestNST(@"@""[Infinity]""", @" + + + + [ + + + Infinity + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_invalid___json() + { + TestNST(@"@""[0e+-1]""", @" + + + + [ + + + 0e+-1 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_invalid_negative_real_json() + { + TestNST(@"@""[-123.123foo]""", @" + + + + [ + + + -123.123foo + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_invalid_utf_8_in_bigger_int_json() + { + TestNST(@"@""[123�]""", @" + + + + [ + + + 123� + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_invalid_utf_8_in_exponent_json() + { + TestNST(@"@""[1e1�]""", @" + + + + [ + + + 1e1� + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_invalid_utf_8_in_int_json() + { + TestNST(@"@""[0�] +""", @" + + + + [ + + + 0� + + + ] + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_minus_infinity_json() + { + TestNST(@"@""[-Infinity]""", @" + + + + [ + + + - + Infinity + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_minus_sign_with_trailing_garbage_json() + { + TestNST(@"@""[-foo]""", @" + + + + [ + + + -foo + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_minus_space_1_json() + { + TestNST(@"@""[- 1]""", @" + + + + [ + + + - + + + 1 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_NaN_json() + { + TestNST(@"@""[NaN]""", @" + + + + [ + + + NaN + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_neg_int_starting_with_zero_json() + { + TestNST(@"@""[-012]""", @" + + + + [ + + + -012 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_neg_real_without_int_part_json() + { + TestNST(@"@""[-.123]""", @" + + + + [ + + + -.123 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_neg_with_garbage_at_end_json() + { + TestNST(@"@""[-1x]""", @" + + + + [ + + + -1x + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_real_garbage_after_e_json() + { + TestNST(@"@""[1ea]""", @" + + + + [ + + + 1ea + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_real_without_fractional_part_json() + { + TestNST(@"@""[1.]""", @" + + + + [ + + + 1. + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_real_with_invalid_utf8_after_e_json() + { + TestNST(@"@""[1e�]""", @" + + + + [ + + + 1e� + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_starting_with_dot_json() + { + TestNST(@"@""[.123]""", @" + + + + [ + + + .123 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_number_U_FF11_fullwidth_digit_one_json() + { + TestNST(@"@""[1]""", @" + + + + [ + + + + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_with_alpha_json() + { + TestNST(@"@""[1.2a-3]""", @" + + + + [ + + + 1.2a-3 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_with_alpha_char_json() + { + TestNST(@"@""[1.8011670033376514H-308]""", @" + + + + [ + + + 1.8011670033376514H-308 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_number_with_leading_zero_json() + { + TestNST(@"@""[012]""", @" + + + + [ + + + 012 + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_bad_value_json() + { + TestNST(@"@""[""""x"""", truth]""", @" + + + + [ + + + ""x"" + + + , + + + truth + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_bracket_key_json() + { + TestNST(@"@""{[: """"x""""} +""", @" + + + + { + + + [ + + + : + + + ""x"" + + + + + + } + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_comma_instead_of_colon_json() + { + TestNST(@"@""{""""x"""", null}""", @" + + + + { + + + ""x"" + + , + + null + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_double_colon_json() + { + TestNST(@"@""{""""x""""::""""b""""}""", @" + + + + { + + + ""x"" + : + + : + + + + + ""b"" + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_garbage_at_end_json() + { + TestNST(@"@""{""""a"""":""""a"""" 123}""", @" + + + + { + + + ""a"" + : + + ""a"" + + + + + 123 + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_key_with_single_quotes_json() + { + TestNST(@"@""{key: 'value'}""", @" + + + + { + + + key + : + + 'value' + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_lone_continuation_byte_in_key_and_trailing_comma_json() + { + TestNST(@"@""{""""�"""":""""0"""",}""", @" + + + + { + + + ""�"" + : + + ""0"" + + + , + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_missing_colon_json() + { + TestNST(@"@""{""""a"""" b}""", @" + + + + { + + + ""a"" + + + + b + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_missing_key_json() + { + TestNST(@"@""{:""""b""""}""", @" + + + + { + + + : + + + + ""b"" + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_missing_semicolon_json() + { + TestNST(@"@""{""""a"""" """"b""""}""", @" + + + + { + + + ""a"" + + + + ""b"" + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_missing_value_json() + { + TestNST(@"@""{""""a"""":""", @" + + + + { + + + ""a"" + : + + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_no_colon_json() + { + TestNST(@"@""{""""a""""""", @" + + + + { + + + ""a"" + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_non_string_key_json() + { + TestNST(@"@""{1:1}""", @" + + + + { + + + 1 + : + + 1 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_non_string_key_but_huge_number_instead_json() + { + TestNST(@"@""{9999E9999:1}""", @" + + + + { + + + 9999E9999 + : + + 1 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_repeated_null_null_json() + { + TestNST(@"@""{null:null,null:null}""", @" + + + + { + + + null + : + + null + + + , + + null + : + + null + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_several_trailing_commas_json() + { + TestNST(@"@""{""""id"""":0,,,,,}""", @" + + + + { + + + ""id"" + : + + 0 + + + , + + , + + , + + , + + , + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_single_quote_json() + { + TestNST(@"@""{'a':0}""", @" + + + + { + + + 'a' + : + + 0 + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_trailing_comma_json() + { + TestNST(@"@""{""""id"""":0,}""", @" + + + + { + + + ""id"" + : + + 0 + + + , + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_trailing_comment_json() + { + TestNST(@"@""{""""a"""":""""b""""}/**/""", @" + + + + { + + + ""a"" + : + + ""b"" + + + + }/**/ + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_trailing_comment_open_json() + { + TestNST(@"@""{""""a"""":""""b""""}/**//""", @" + + + + { + + + ""a"" + : + + ""b"" + + + + }/**// + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_trailing_comment_slash_open_json() + { + TestNST(@"@""{""""a"""":""""b""""}//""", @" + + + + { + + + ""a"" + : + + ""b"" + + + + }// + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_trailing_comment_slash_open_incomplete_json() + { + TestNST(@"@""{""""a"""":""""b""""}/""", @" + + + + { + + + ""a"" + : + + ""b"" + + + + }/ + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_two_commas_in_a_row_json() + { + TestNST(@"@""{""""a"""":""""b"""",,""""c"""":""""d""""}""", @" + + + + { + + + ""a"" + : + + ""b"" + + + , + + , + + + + ""c"" + : + + ""d"" + + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_unquoted_key_json() + { + TestNST(@"@""{a: """"b""""}""", @" + + + + { + + + a + : + + ""b"" + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_object_unterminated_value_json() + { + TestNST(@"@""{""""a"""":""""a""", @" + + + + { + + + ""a"" + : + + ""a + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_with_single_string_json() + { + TestNST(@"@""{ """"foo"""" : """"bar"""", """"a"""" }""", @" + + + + { + + + ""foo"" + : + + ""bar"" + + + , + + ""a"" + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_object_with_trailing_garbage_json() + { + TestNST(@"@""{""""a"""":""""b""""}#""", @" + + + + { + + + ""a"" + : + + ""b"" + + + + } + + + # + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_single_space_json() + { + TestNST(@"@"" """, @" + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_1_surrogate_then_escape_json() + { + TestNST(@"@""[""""\uD800\""""]""", @" + + + + [ + + + ""\uD800\""] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_1_surrogate_then_escape_u_json() + { + TestNST(@"@""[""""\uD800\u""""]""", @" + + + + [ + + + ""\uD800\u""] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_1_surrogate_then_escape_u1_json() + { + TestNST(@"@""[""""\uD800\u1""""]""", @" + + + + [ + + + ""\uD800\u1""] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_1_surrogate_then_escape_u1x_json() + { + TestNST(@"@""[""""\uD800\u1x""""]""", @" + + + + [ + + + ""\uD800\u1x""] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_accentuated_char_no_quotes_json() + { + TestNST(@"@""[é]""", @" + + + + [ + + + é + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_escaped_backslash_bad_json() + { + TestNST(@"@""[""""\\\""""]""", @" + + + + [ + + + ""\\\""] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_escaped_ctrl_char_tab_json() + { + TestNST(@"@""[""""\ """"]""", @" + + + + [ + + + ""\ "" + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_escaped_emoji_json() + { + TestNST(@"@""[""""\🌀""""]""", @" + + + + [ + + + ""\🌀"" + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_escape_x_json() + { + TestNST(@"@""[""""\x00""""]""", @" + + + + [ + + + ""\x00"" + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_incomplete_escape_json() + { + TestNST(@"@""[""""\""""]""", @" + + + + [ + + + ""\""] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_incomplete_escaped_character_json() + { + TestNST(@"@""[""""\u00A""""]""", @" + + + + [ + + + ""\u00A""] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_incomplete_surrogate_json() + { + TestNST(@"@""[""""\uD834\uDd""""]""", @" + + + + [ + + + ""\uD834\uDd""] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_incomplete_surrogate_escape_invalid_json() + { + TestNST(@"@""[""""\uD800\uD800\x""""]""", @" + + + + [ + + + ""\uD800\uD800\x"" + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_invalid_utf_8_in_escape_json() + { + TestNST(@"@""[""""\u�""""]""", @" + + + + [ + + + ""\u�""] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_invalid_backslash_esc_json() + { + TestNST(@"@""[""""\a""""]""", @" + + + + [ + + + ""\a"" + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_invalid_unicode_escape_json() + { + TestNST(@"@""[""""\uqqqq""""]""", @" + + + + [ + + + ""\uqqqq"" + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_invalid_utf8_after_escape_json() + { + TestNST(@"@""[""""\�""""]""", @" + + + + [ + + + ""\�"" + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_leading_uescaped_thinspace_json() + { + TestNST(@"@""[\u0020""""asd""""]""", @" + + + + [ + + + \u0020 + + + ""asd"" + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_no_quotes_with_bad_escape_json() + { + TestNST(@"@""[\n]""", @" + + + + [ + + + \n + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_single_doublequote_json() + { + TestNST(@"@""""""""", @" + + + + "" + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_single_quote_json() + { + TestNST(@"@""['single quote']""", @" + + + + [ + + + 'single quote' + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_string_single_string_no_double_quotes_json() + { + TestNST(@"@""abc""", @" + + + + abc + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_start_escape_unclosed_json() + { + TestNST(@"@""[""""\""", @" + + + + [ + + + ""\ + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_unescaped_newline_json() + { + TestNST(@"@""[""""new +line""""]""", @" + + + + [ + + + ""new +line"" + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_string_unescaped_tab_json() + { + TestNST(@"@""["""" """"]""", @" + + + + [ + + + "" "" + + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_string_unicode_CapitalU_json() + { + TestNST(@"@""""""\UA66D""""""", @" + + + + ""\UA66D"" + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_string_with_trailing_garbage_json() + { + TestNST(@"@""""""""""x""", @" + + + + """" + + + x + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_angle_bracket___json() + { + TestNST(@"@""<.>""", @" + + + + <.> + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_angle_bracket_null_json() + { + TestNST(@"@""[]""", @" + + + + [ + + + <null> + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_array_trailing_garbage_json() + { + TestNST(@"@""[1]x""", @" + + + + [ + + + 1 + + + ] + + + x + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_array_with_extra_array_close_json() + { + TestNST(@"@""[1]]""", @" + + + + [ + + + 1 + + + ] + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_array_with_unclosed_string_json() + { + TestNST(@"@""[""""asd]""", @" + + + + [ + + + ""asd] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_ascii_unicode_identifier_json() + { + TestNST(@"@""aå""", @" + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_capitalized_True_json() + { + TestNST(@"@""[True]""", @" + + + + [ + + + True + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_close_unopened_array_json() + { + TestNST(@"@""1]""", @" + + + + 1 + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_comma_instead_of_closing_brace_json() + { + TestNST(@"@""{""""x"""": true,""", @" + + + + { + + + ""x"" + : + + true + + + , + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_double_array_json() + { + TestNST(@"@""[][]""", @" + + + + [ + + ] + + + [ + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_end_array_json() + { + TestNST(@"@""]""", @" + + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_incomplete_UTF8_BOM_json() + { + TestNST(@"@""�{}""", @" + + + + + + + { + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_lone_open_bracket_json() + { + TestNST(@"@""[""", @" + + + + [ + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_number_with_trailing_garbage_json() + { + TestNST(@"@""2@""", @" + + + + 2@ + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_object_followed_by_closing_object_json() + { + TestNST(@"@""{}}""", @" + + + + { + + } + + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_object_unclosed_no_value_json() + { + TestNST(@"@""{"""""""":""", @" + + + + { + + + """" + : + + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_object_with_comment_json() + { + TestNST(@"@""{""""a"""":/*comment*/""""b""""}""", @" + + + + { + + + ""a"" + :/*comment*/ + + ""b"" + + + + } + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_structure_object_with_trailing_garbage_json() + { + TestNST(@"@""{""""a"""": true} """"x""""""", @" + + + + { + + + ""a"" + : + + true + + + + } + + + ""x"" + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_array_apostrophe_json() + { + TestNST(@"@""['""", @" + + + + [ + + + ' + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_array_comma_json() + { + TestNST(@"@""[,""", @" + + + + [ + + + , + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_array_open_object_json() + { + TestNST(@"@""[{""", @" + + + + [ + + + { + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_array_open_string_json() + { + TestNST(@"@""[""""a""", @" + + + + [ + + + ""a + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_array_string_json() + { + TestNST(@"@""[""""a""""""", @" + + + + [ + + + ""a"" + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_object_json() + { + TestNST(@"@""{""", @" + + + + { + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_object_close_array_json() + { + TestNST(@"@""{]""", @" + + + + { + + + ] + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_object_comma_json() + { + TestNST(@"@""{,""", @" + + + + { + + + , + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_object_open_array_json() + { + TestNST(@"@""{[""", @" + + + + { + + + [ + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_object_open_string_json() + { + TestNST(@"@""{""""a""", @" + + + + { + + + ""a + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_object_string_with_apostrophes_json() + { + TestNST(@"@""{'a'""", @" + + + + { + + + 'a' + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_open_open_json() + { + TestNST(@"@""[""""\{[""""\{[""""\{[""""\{""", @" + + + + [ + + + ""\{["" + + + \ + + + { + + + [ + + + ""\{["" + + + \ + + + { + + + + + + + + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_single_star_json() + { + TestNST(@"@""*""", @" + + + + * + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_trailing___json() + { + TestNST(@"@""{""""a"""":""""b""""}#{}""", @" + + + + { + + + ""a"" + : + + ""b"" + + + + } + + + # + + + { + + } + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_U_2060_word_joined_json() + { + TestNST(@"@""[⁠]""", @" + + + + [ + + + + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_uescaped_LF_before_string_json() + { + TestNST(@"@""[\u000A""""""""]""", @" + + + + [ + + + \u000A + + + """" + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_unclosed_array_json() + { + TestNST(@"@""[1""", @" + + + + [ + + + 1 + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_unclosed_array_partial_null_json() + { + TestNST(@"@""[ false, nul""", @" + + + + [ + + + false + + + , + + + nul + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_unclosed_array_unfinished_false_json() + { + TestNST(@"@""[ true, fals""", @" + + + + [ + + + true + + + , + + + fals + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_unclosed_array_unfinished_true_json() + { + TestNST(@"@""[ false, tru""", @" + + + + [ + + + false + + + , + + + tru + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_unclosed_object_json() + { + TestNST(@"@""{""""asd"""":""""asd""""""", @" + + + + { + + + ""asd"" + : + + ""asd"" + + + + + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_unicode_identifier_json() + { + TestNST(@"@""å""", @" + + + + å + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void n_structure_whitespace_formfeed_json() + { + TestNST(@"@""[ ]""", @" + + + + [\f + + ] + + + + +", + @"", + @" + +"); + } + + [Fact] + public void n_structure_whitespace_U_2060_word_joiner_json() + { + TestNST(@"@""[⁠]""", @" + + + + [ + + + + + + ] + + + + +", + @" + +", + @" + +"); + } + + [Fact] + public void y_array_arraysWithSpaces_json() + { + TestNST(@"@""[[] ]""", @" + + + + [ + + + [ + + ] + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_empty_string_json() + { + TestNST(@"@""[""""""""]""", @" + + + + [ + + + """" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_empty_json() + { + TestNST(@"@""[]""", @" + + + + [ + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_ending_with_newline_json() + { + TestNST(@"@""[""""a""""]""", @" + + + + [ + + + ""a"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_false_json() + { + TestNST(@"@""[false]""", @" + + + + [ + + + false + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_heterogeneous_json() + { + TestNST(@"@""[null, 1, """"1"""", {}]""", @" + + + + [ + + + null + + + , + + + 1 + + + , + + + ""1"" + + + , + + + { + + } + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_null_json() + { + TestNST(@"@""[null]""", @" + + + + [ + + + null + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_with_1_and_newline_json() + { + TestNST(@"@""[1 +]""", @" + + + + [ + + + 1 + + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_with_leading_space_json() + { + TestNST(@"@"" [1]""", @" + + + + + + + [ + + + 1 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_with_several_null_json() + { + TestNST(@"@""[1,null,null,null,2]""", @" + + + + [ + + + 1 + + + , + + + null + + + , + + + null + + + , + + + null + + + , + + + 2 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_array_with_trailing_space_json() + { + TestNST(@"@""[2] """, @" + + + + [ + + + 2 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_json() + { + TestNST(@"@""[123e65]""", @" + + + + [ + + + 123e65 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_0e_1_json() + { + TestNST(@"@""[0e+1]""", @" + + + + [ + + + 0e+1 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_0e1_json() + { + TestNST(@"@""[0e1]""", @" + + + + [ + + + 0e1 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_after_space_json() + { + TestNST(@"@""[ 4]""", @" + + + + [ + + + 4 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_double_close_to_zero_json() + { + TestNST(@"@""[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] +""", @" + + + + [ + + + -0.000000000000000000000000000000000000000000000000000000000000000000000000000001 + + + ] + + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_int_with_exp_json() + { + TestNST(@"@""[20e1]""", @" + + + + [ + + + 20e1 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_minus_zero_json() + { + TestNST(@"@""[-0]""", @" + + + + [ + + + -0 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_negative_int_json() + { + TestNST(@"@""[-123]""", @" + + + + [ + + + -123 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_negative_one_json() + { + TestNST(@"@""[-1]""", @" + + + + [ + + + -1 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_negative_zero_json() + { + TestNST(@"@""[-0]""", @" + + + + [ + + + -0 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_real_capital_e_json() + { + TestNST(@"@""[1E22]""", @" + + + + [ + + + 1E22 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_real_capital_e_neg_exp_json() + { + TestNST(@"@""[1E-2]""", @" + + + + [ + + + 1E-2 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_real_capital_e_pos_exp_json() + { + TestNST(@"@""[1E+2]""", @" + + + + [ + + + 1E+2 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_real_exponent_json() + { + TestNST(@"@""[123e45]""", @" + + + + [ + + + 123e45 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_real_fraction_exponent_json() + { + TestNST(@"@""[123.456e78]""", @" + + + + [ + + + 123.456e78 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_real_neg_exp_json() + { + TestNST(@"@""[1e-2]""", @" + + + + [ + + + 1e-2 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_real_pos_exponent_json() + { + TestNST(@"@""[1e+2]""", @" + + + + [ + + + 1e+2 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_simple_int_json() + { + TestNST(@"@""[123]""", @" + + + + [ + + + 123 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_number_simple_real_json() + { + TestNST(@"@""[123.456789]""", @" + + + + [ + + + 123.456789 + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_json() + { + TestNST(@"@""{""""asd"""":""""sdf"""", """"dfg"""":""""fgh""""}""", @" + + + + { + + + ""asd"" + : + + ""sdf"" + + + , + + ""dfg"" + : + + ""fgh"" + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_basic_json() + { + TestNST(@"@""{""""asd"""":""""sdf""""}""", @" + + + + { + + + ""asd"" + : + + ""sdf"" + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_duplicated_key_json() + { + TestNST(@"@""{""""a"""":""""b"""",""""a"""":""""c""""}""", @" + + + + { + + + ""a"" + : + + ""b"" + + + , + + ""a"" + : + + ""c"" + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_duplicated_key_and_value_json() + { + TestNST(@"@""{""""a"""":""""b"""",""""a"""":""""b""""}""", @" + + + + { + + + ""a"" + : + + ""b"" + + + , + + ""a"" + : + + ""b"" + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_empty_json() + { + TestNST(@"@""{}""", @" + + + + { + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_empty_key_json() + { + TestNST(@"@""{"""""""":0}""", @" + + + + { + + + """" + : + + 0 + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_escaped_null_in_key_json() + { + TestNST(@"@""{""""foo\u0000bar"""": 42}""", @" + + + + { + + + ""foo\u0000bar"" + : + + 42 + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_extreme_numbers_json() + { + TestNST(@"@""{ """"min"""": -1.0e+28, """"max"""": 1.0e+28 }""", @" + + + + { + + + ""min"" + : + + -1.0e+28 + + + , + + ""max"" + : + + 1.0e+28 + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_long_strings_json() + { + TestNST(@"@""{""""x"""":[{""""id"""": """"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx""""}], """"id"""": """"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx""""}""", + @" + + + + { + + + ""x"" + : + + [ + + + { + + + ""id"" + : + + ""xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"" + + + + } + + + ] + + + , + + ""id"" + : + + ""xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"" + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_simple_json() + { + TestNST(@"@""{""""a"""":[]}""", @" + + + + { + + + ""a"" + : + + [ + + ] + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_string_unicode_json() + { + TestNST(@"@""{""""title"""":""""\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430"""" }""", @" + + + + { + + + ""title"" + : + + ""\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430"" + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_object_with_newlines_json() + { + TestNST(@"@""{ +""""a"""": """"b"""" +}""", @" + + + + { + + + + ""a"" + : + + ""b"" + + + + + } + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_1_2_3_bytes_UTF_8_sequences_json() + { + TestNST(@"@""[""""\u0060\u012a\u12AB""""]""", @" + + + + [ + + + ""\u0060\u012a\u12AB"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_accepted_surrogate_pair_json() + { + TestNST(@"@""[""""\uD801\udc37""""]""", @" + + + + [ + + + ""\uD801\udc37"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_accepted_surrogate_pairs_json() + { + TestNST(@"@""[""""\ud83d\ude39\ud83d\udc8d""""]""", @" + + + + [ + + + ""\ud83d\ude39\ud83d\udc8d"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_allowed_escapes_json() + { + TestNST(@"@""[""""\""""\\\/\b\f\n\r\t""""]""", @" + + + + [ + + + ""\""\\\/\b\f\n\r\t"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_backslash_and_u_escaped_zero_json() + { + TestNST(@"@""[""""\\u0000""""]""", @" + + + + [ + + + ""\\u0000"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_backslash_doublequotes_json() + { + TestNST(@"@""[""""\""""""""]""", @" + + + + [ + + + ""\"""" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_comments_json() + { + TestNST(@"@""[""""a/*b*/c/*d//e""""]""", @" + + + + [ + + + ""a/*b*/c/*d//e"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_double_escape_a_json() + { + TestNST(@"@""[""""\\a""""]""", @" + + + + [ + + + ""\\a"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_double_escape_n_json() + { + TestNST(@"@""[""""\\n""""]""", @" + + + + [ + + + ""\\n"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_escaped_control_character_json() + { + TestNST(@"@""[""""\u0012""""]""", @" + + + + [ + + + ""\u0012"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_escaped_noncharacter_json() + { + TestNST(@"@""[""""\uFFFF""""]""", @" + + + + [ + + + ""\uFFFF"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_in_array_json() + { + TestNST(@"@""[""""asd""""]""", @" + + + + [ + + + ""asd"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_in_array_with_leading_space_json() + { + TestNST(@"@""[ """"asd""""]""", @" + + + + [ + + + ""asd"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_last_surrogates_1_and_2_json() + { + TestNST(@"@""[""""\uDBFF\uDFFF""""]""", @" + + + + [ + + + ""\uDBFF\uDFFF"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_nbsp_uescaped_json() + { + TestNST(@"@""[""""new\u00A0line""""]""", @" + + + + [ + + + ""new\u00A0line"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_nonCharacterInUTF_8_U_10FFFF_json() + { + TestNST(@"@""[""""􏿿""""]""", @" + + + + [ + + + ""􏿿"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_null_escape_json() + { + TestNST(@"@""[""""\u0000""""]""", @" + + + + [ + + + ""\u0000"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_one_byte_utf_8_json() + { + TestNST(@"@""[""""\u002c""""]""", @" + + + + [ + + + ""\u002c"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_pi_json() + { + TestNST(@"@""[""""π""""]""", @" + + + + [ + + + ""π"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_reservedCharacterInUTF_8_U_1BFFF_json() + { + TestNST(@"@""[""""𛿿""""]""", @" + + + + [ + + + ""𛿿"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_simple_ascii_json() + { + TestNST(@"@""[""""asd """"]""", @" + + + + [ + + + ""asd "" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_space_json() + { + TestNST(@"@"""""" """"""", @" + + + + "" "" + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_surrogates_U_1D11E_MUSICAL_SYMBOL_G_CLEF_json() + { + TestNST(@"@""[""""\uD834\uDd1e""""]""", @" + + + + [ + + + ""\uD834\uDd1e"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_three_byte_utf_8_json() + { + TestNST(@"@""[""""\u0821""""]""", @" + + + + [ + + + ""\u0821"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_two_byte_utf_8_json() + { + TestNST(@"@""[""""\u0123""""]""", @" + + + + [ + + + ""\u0123"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_u_2028_line_sep_json() + { + TestNST(@"@""[""""
""""]""", @" + + + + [ + + + ""
"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_u_2029_par_sep_json() + { + TestNST(@"@""[""""
""""]""", @" + + + + [ + + + ""
"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_uEscape_json() + { + TestNST(@"@""[""""\u0061\u30af\u30EA\u30b9""""]""", @" + + + + [ + + + ""\u0061\u30af\u30EA\u30b9"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_uescaped_newline_json() + { + TestNST(@"@""[""""new\u000Aline""""]""", @" + + + + [ + + + ""new\u000Aline"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unescaped_char_delete_json() + { + TestNST(@"@""[""""""""]""", @" + + + + [ + + + """" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicode_json() + { + TestNST(@"@""[""""\uA66D""""]""", @" + + + + [ + + + ""\uA66D"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicodeEscapedBackslash_json() + { + TestNST(@"@""[""""\u005C""""]""", @" + + + + [ + + + ""\u005C"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicode_2_json() + { + TestNST(@"@""[""""⍂㈴⍂""""]""", @" + + + + [ + + + ""⍂㈴⍂"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicode_escaped_double_quote_json() + { + TestNST(@"@""[""""\u0022""""]""", @" + + + + [ + + + ""\u0022"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicode_U_10FFFE_nonchar_json() + { + TestNST(@"@""[""""\uDBFF\uDFFE""""]""", @" + + + + [ + + + ""\uDBFF\uDFFE"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicode_U_1FFFE_nonchar_json() + { + TestNST(@"@""[""""\uD83F\uDFFE""""]""", @" + + + + [ + + + ""\uD83F\uDFFE"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicode_U_200B_ZERO_WIDTH_SPACE_json() + { + TestNST(@"@""[""""\u200B""""]""", @" + + + + [ + + + ""\u200B"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicode_U_2064_invisible_plus_json() + { + TestNST(@"@""[""""\u2064""""]""", @" + + + + [ + + + ""\u2064"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicode_U_FDD0_nonchar_json() + { + TestNST(@"@""[""""\uFDD0""""]""", @" + + + + [ + + + ""\uFDD0"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_unicode_U_FFFE_nonchar_json() + { + TestNST(@"@""[""""\uFFFE""""]""", @" + + + + [ + + + ""\uFFFE"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_utf8_json() + { + TestNST(@"@""[""""€𝄞""""]""", @" + + + + [ + + + ""€𝄞"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_string_with_del_character_json() + { + TestNST(@"@""[""""aa""""]""", @" + + + + [ + + + ""aa"" + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_lonely_false_json() + { + TestNST(@"@""false""", @" + + + + false + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_lonely_int_json() + { + TestNST(@"@""42""", @" + + + + 42 + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_lonely_negative_real_json() + { + TestNST(@"@""-0.1""", @" + + + + -0.1 + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_lonely_null_json() + { + TestNST(@"@""null""", @" + + + + null + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_lonely_string_json() + { + TestNST(@"@""""""asd""""""", @" + + + + ""asd"" + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_lonely_true_json() + { + TestNST(@"@""true""", @" + + + + true + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_string_empty_json() + { + TestNST(@"@""""""""""""", @" + + + + """" + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_trailing_newline_json() + { + TestNST(@"@""[""""a""""] +""", @" + + + + [ + + + ""a"" + + + ] + + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_true_in_array_json() + { + TestNST(@"@""[true]""", @" + + + + [ + + + true + + + ] + + + + +", + @"", + @""); + } + + [Fact] + public void y_structure_whitespace_array_json() + { + TestNST(@"@"" [] """, @" + + + + + + + [ + + ] + + + + +", + @"", + @""); + } + } +} diff --git a/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonTests.cs new file mode 100644 index 0000000000000..326fdb7dec495 --- /dev/null +++ b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonTests.cs @@ -0,0 +1,394 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Text.Json; +using System.Xml.Linq; +using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.EmbeddedLanguages.Json +{ + using JsonSeparatedList = EmbeddedSeparatedSyntaxNodeList; + using JsonToken = EmbeddedSyntaxToken; + using JsonTrivia = EmbeddedSyntaxTrivia; + + public partial class CSharpJsonParserTests + { + private readonly IVirtualCharService _service = CSharpVirtualCharService.Instance; + private const string StatementPrefix = "var v = "; + + private static SyntaxToken GetStringToken(string text) + { + var statement = StatementPrefix + text; + var parsedStatement = SyntaxFactory.ParseStatement(statement); + var token = parsedStatement.DescendantTokens().ToArray()[3]; + Assert.True(token.Kind() == SyntaxKind.StringLiteralToken); + + return token; + } + + protected void Test( + string stringText, + string? expected, + string looseDiagnostics, + string strictDiagnostics, + bool runLooseSubTreeCheck = true) + { + Test(stringText, JsonOptions.Loose, expected, looseDiagnostics, runLooseSubTreeCheck); + Test(stringText, JsonOptions.Strict, expected, strictDiagnostics, runSubTreeChecks: true); + } + + private void Test( + string stringText, JsonOptions options, + string? expectedTree, string expectedDiagnostics, + bool runSubTreeChecks) + { + var tree = TryParseTree(stringText, options, conversionFailureOk: false); + if (tree == null) + { + Assert.Null(expectedTree); + return; + } + + Assert.NotNull(expectedTree); + + // Tests are allowed to not run the subtree tests. This is because some + // subtrees can cause the native regex parser to exhibit very bad behavior + // (like not ever actually finishing compiling). + if (runSubTreeChecks) + TryParseSubTrees(stringText, options); + + var actualTree = TreeToText(tree).Replace("\"", "\"\""); + Assert.Equal(expectedTree!.Replace("\"", "\"\""), actualTree); + + var actualDiagnostics = DiagnosticsToText(tree.Diagnostics).Replace("\"", "\"\""); + Assert.Equal(expectedDiagnostics.Replace("\"", "\"\""), actualDiagnostics); + } + + private void TryParseSubTrees(string stringText, JsonOptions options) + { + // Trim the input from the right and make sure tree invariants hold + var current = stringText; + while (current != "@\"\"" && current != "\"\"") + { + current = current[0..^2] + "\""; + TryParseTree(current, options, conversionFailureOk: true); + } + + // Trim the input from the left and make sure tree invariants hold + current = stringText; + while (current != "@\"\"" && current != "\"\"") + { + current = current[0] == '@' + ? "@\"" + current[3..] + : "\"" + current[2..]; + + TryParseTree(current, options, conversionFailureOk: true); + } + + for (var start = stringText[0] == '@' ? 2 : 1; start < stringText.Length - 1; start++) + { + TryParseTree( + stringText[..start] + stringText[(start + 1)..], + options, conversionFailureOk: true); + } + } + + private protected (SyntaxToken, JsonTree?, VirtualCharSequence) JustParseTree( + string stringText, JsonOptions options, bool conversionFailureOk) + { + var token = GetStringToken(stringText); + if (token.ValueText == "") + return default; + + var allChars = _service.TryConvertToVirtualChars(token); + if (allChars.IsDefault) + { + Assert.True(conversionFailureOk, "Failed to convert text to token."); + return (token, null, allChars); + } + + var tree = JsonParser.TryParse(allChars, options); + return (token, tree, allChars); + } + + private JsonTree? TryParseTree( + string stringText, JsonOptions options, bool conversionFailureOk) + { + var (token, tree, allChars) = JustParseTree(stringText, options, conversionFailureOk); + if (tree == null) + { + Assert.True(allChars.IsDefault); + return null; + } + + CheckInvariants(tree, allChars); + + if (options == JsonOptions.Loose) + { + try + { + JToken.Parse(token.ValueText); + } + catch (Exception) + { + Assert.NotEmpty(tree.Diagnostics); + return tree; + } + } + else + { + try + { + JsonDocument.Parse(token.ValueText, new JsonDocumentOptions { AllowTrailingCommas = false, CommentHandling = JsonCommentHandling.Disallow }); + } + catch (Exception) + { + Assert.NotEmpty(tree.Diagnostics); + return tree; + } + } + + Assert.Empty(tree.Diagnostics); + return tree; + } + + private protected static string TreeToText(JsonTree tree) + => new XElement("Tree", + NodeToElement(tree.Root)).ToString(); + + private protected static string DiagnosticsToText(ImmutableArray diagnostics) + { + if (diagnostics.IsEmpty) + return ""; + + return new XElement("Diagnostics", + diagnostics.Select(d => + new XElement("Diagnostic", + new XAttribute("Message", d.Message), + new XAttribute("Start", d.Span.Start), + new XAttribute("Length", d.Span.Length)))).ToString(); + } + + private static XElement NodeToElement(JsonNode node) + { + if (node is JsonArrayNode arrayNode) + return ArrayNodeToElement(arrayNode); + + if (node is JsonCompilationUnit compilationUnit) + return CompilationUnitToElement(compilationUnit); + + if (node is JsonObjectNode objectNode) + return ObjectNodeToElement(objectNode); + + if (node is JsonConstructorNode constructorNode) + return ConstructorNodeToElement(constructorNode); + + var element = new XElement(node.Kind.ToString()); + foreach (var child in node) + element.Add(NodeOrTokenToElement(child)); + + return element; + } + + private static XElement NodeOrTokenToElement(EmbeddedSyntaxNodeOrToken child) + { + return child.IsNode ? NodeToElement(child.Node) : TokenToElement(child.Token); + } + + private static XElement ConstructorNodeToElement(JsonConstructorNode node) + { + var element = new XElement(node.Kind.ToString()); + element.Add(TokenToElement(node.NewKeyword)); + element.Add(TokenToElement(node.NameToken)); + element.Add(TokenToElement(node.OpenParenToken)); + element.Add(CreateSequenceNode(node.Sequence)); + element.Add(TokenToElement(node.CloseParenToken)); + return element; + } + + private static XElement ObjectNodeToElement(JsonObjectNode node) + { + var element = new XElement(node.Kind.ToString()); + element.Add(TokenToElement(node.OpenBraceToken)); + element.Add(CreateSequenceNode(node.Sequence)); + element.Add(TokenToElement(node.CloseBraceToken)); + return element; + } + + private static XElement CompilationUnitToElement(JsonCompilationUnit node) + { + var element = new XElement(node.Kind.ToString()); + element.Add(CreateSequenceNode(node.Sequence)); + element.Add(TokenToElement(node.EndOfFileToken)); + return element; + } + + private static XElement ArrayNodeToElement(JsonArrayNode node) + { + var element = new XElement(node.Kind.ToString()); + element.Add(TokenToElement(node.OpenBracketToken)); + element.Add(CreateSequenceNode(node.Sequence)); + element.Add(TokenToElement(node.CloseBracketToken)); + return element; + } + + private static XElement CreateSequenceNode(ImmutableArray sequence) + { + var element = new XElement("Sequence"); + foreach (var child in sequence) + element.Add(NodeToElement(child)); + return element; + } + + private static XElement CreateSequenceNode(JsonSeparatedList sequence) + { + var element = new XElement("Sequence"); + foreach (var child in sequence.NodesAndTokens) + element.Add(NodeOrTokenToElement(child)); + return element; + } + + private static XElement TokenToElement(JsonToken token) + { + var element = new XElement(token.Kind.ToString()); + + if (token.Value != null) + element.Add(new XAttribute("value", token.Value)); + + if (token.LeadingTrivia.Length > 0) + element.Add(new XElement("Trivia", token.LeadingTrivia.Select(t => TriviaToElement(t)))); + + if (token.VirtualChars.Length > 0) + element.Add(token.VirtualChars.CreateString()); + + if (token.TrailingTrivia.Length > 0) + element.Add(new XElement("Trivia", token.TrailingTrivia.Select(t => TriviaToElement(t)))); + + return element; + } + + private static XElement TriviaToElement(JsonTrivia trivia) + => new( + trivia.Kind.ToString(), + trivia.VirtualChars.CreateString().Replace("\f", "\\f")); + + private protected static void CheckInvariants(JsonTree tree, VirtualCharSequence allChars) + { + var root = tree.Root; + var position = 0; + CheckInvariants(root, ref position, allChars); + Assert.Equal(allChars.Length, position); + } + + private static void CheckInvariants(JsonNode node, ref int position, VirtualCharSequence allChars) + { + foreach (var child in node) + { + if (child.IsNode) + { + CheckInvariants(child.Node, ref position, allChars); + } + else + { + CheckInvariants(child.Token, ref position, allChars); + } + } + } + + private static void CheckInvariants(JsonToken token, ref int position, VirtualCharSequence allChars) + { + CheckInvariants(token.LeadingTrivia, ref position, allChars); + CheckCharacters(token.VirtualChars, ref position, allChars); + CheckInvariants(token.TrailingTrivia, ref position, allChars); + } + + private static void CheckInvariants(ImmutableArray leadingTrivia, ref int position, VirtualCharSequence allChars) + { + foreach (var trivia in leadingTrivia) + CheckInvariants(trivia, ref position, allChars); + } + + private static void CheckInvariants(JsonTrivia trivia, ref int position, VirtualCharSequence allChars) + { + switch (trivia.Kind) + { + case JsonKind.SingleLineCommentTrivia: + case JsonKind.MultiLineCommentTrivia: + case JsonKind.WhitespaceTrivia: + case JsonKind.EndOfLineTrivia: + break; + default: + Assert.False(true, "Incorrect trivia kind"); + return; + } + + CheckCharacters(trivia.VirtualChars, ref position, allChars); + } + + private static void CheckCharacters(VirtualCharSequence virtualChars, ref int position, VirtualCharSequence allChars) + { + for (var i = 0; i < virtualChars.Length; i++) + Assert.Equal(allChars[position + i], virtualChars[i]); + + position += virtualChars.Length; + } + + private object RemoveSequenceNode(XNode node) + { + if (node is not XElement element) + return node; + + var children = element.Nodes().Select(RemoveSequenceNode); + + if (element.Name == "Sequence") + return children; + return new XElement(element.Name, children); + } + + [Fact] + public void TestDeepRecursion() + { + var (token, tree, chars) = + JustParseTree( +@"@""[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[""", +JsonOptions.Loose, conversionFailureOk: false); + Assert.False(token.IsMissing); + Assert.False(chars.IsDefaultOrEmpty); + Assert.Null(tree); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests.cs similarity index 96% rename from src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests.cs rename to src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests.cs index ca11699a30eaf..3076ab7447f5b 100644 --- a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests.cs +++ b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests.cs @@ -127,7 +127,7 @@ private void TryParseSubTrees( bool conversionFailureOk, bool allowIndexOutOfRange, bool allowNullReference, - bool allowOutOfMemeory, + bool allowOutOfMemory, bool allowDiagnosticsMismatch = false) { var (token, tree, allChars) = JustParseTree(stringText, options, conversionFailureOk); @@ -157,7 +157,7 @@ private void TryParseSubTrees( // bug with .NET regex parser. can happen with patterns like: (?(?S)) return treeAndText; } - catch (OutOfMemoryException) when (allowOutOfMemeory) + catch (OutOfMemoryException) when (allowOutOfMemory) { // bug with .NET regex parser. can happen with patterns like: a{2147483647,} return treeAndText; @@ -196,7 +196,7 @@ private void TryParseSubTrees( return treeAndText; } - private string TreeToText(SourceText text, RegexTree tree) + private static string TreeToText(SourceText text, RegexTree tree) { var element = new XElement("Tree", NodeToElement(tree.Root)); @@ -226,7 +226,7 @@ private static XElement CreateDiagnosticsElement(SourceText text, RegexTree tree private static XAttribute GetTextAttribute(SourceText text, TextSpan span) => new("Text", text.ToString(span)); - private XElement NodeToElement(RegexNode node) + private static XElement NodeToElement(RegexNode node) { if (node is RegexAlternationNode alternationNode) return AlternationToElement(alternationNode, alternationNode.SequenceList.NodesAndTokens.Length); @@ -238,7 +238,7 @@ private XElement NodeToElement(RegexNode node) return element; } - private XElement AlternationToElement(RegexAlternationNode alternationNode, int end) + private static XElement AlternationToElement(RegexAlternationNode alternationNode, int end) { // to keep tests in sync with how we used to structure alternations, we specially handle this node. // First, if the node only has a single element, then just print that element as that's what would @@ -280,7 +280,7 @@ private static XElement TriviaToElement(RegexTrivia trivia) trivia.Kind.ToString(), trivia.VirtualChars.CreateString()); - private void CheckInvariants(RegexTree tree, VirtualCharSequence allChars) + private static void CheckInvariants(RegexTree tree, VirtualCharSequence allChars) { var root = tree.Root; var position = 0; @@ -288,7 +288,7 @@ private void CheckInvariants(RegexTree tree, VirtualCharSequence allChars) Assert.Equal(allChars.Length, position); } - private void CheckInvariants(RegexNode node, ref int position, VirtualCharSequence allChars) + private static void CheckInvariants(RegexNode node, ref int position, VirtualCharSequence allChars) { foreach (var child in node) { diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_BasicTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_BasicTests.cs similarity index 100% rename from src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_BasicTests.cs rename to src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_BasicTests.cs diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_DotnetNegativeTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_DotnetNegativeTests.cs similarity index 100% rename from src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_DotnetNegativeTests.cs rename to src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_DotnetNegativeTests.cs diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_RealWorld.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_RealWorld.cs similarity index 100% rename from src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_RealWorld.cs rename to src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_RealWorld.cs diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_ReferenceTests.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_ReferenceTests.cs similarity index 100% rename from src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_ReferenceTests.cs rename to src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_ReferenceTests.cs diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_TestGeneration.cs b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_TestGeneration.cs similarity index 100% rename from src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_TestGeneration.cs rename to src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests_TestGeneration.cs diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/Regex_RealWorldPatterns.json b/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/Regex_RealWorldPatterns.json similarity index 100% rename from src/EditorFeatures/CSharpTest/EmbeddedLanguages/RegularExpressions/Regex_RealWorldPatterns.json rename to src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/Regex_RealWorldPatterns.json diff --git a/src/EditorFeatures/CSharpTest2/Microsoft.CodeAnalysis.CSharp.EditorFeatures2.UnitTests.csproj b/src/EditorFeatures/CSharpTest2/Microsoft.CodeAnalysis.CSharp.EditorFeatures2.UnitTests.csproj index 5f58102ba14ca..d548973801f31 100644 --- a/src/EditorFeatures/CSharpTest2/Microsoft.CodeAnalysis.CSharp.EditorFeatures2.UnitTests.csproj +++ b/src/EditorFeatures/CSharpTest2/Microsoft.CodeAnalysis.CSharp.EditorFeatures2.UnitTests.csproj @@ -8,6 +8,9 @@ Library Microsoft.CodeAnalysis.Editor.CSharp.UnitTests + + + diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/AsKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/AsKeywordRecommenderTests.cs index 1c9fb6bf8ea01..aa237db1658e5 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/AsKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/AsKeywordRecommenderTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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; @@ -244,5 +242,56 @@ void M() } }"); } + + [WorkItem(31367, "https://github.com/dotnet/roslyn/issues/31367")] + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestMissingInCaseClause1() + { + await VerifyAbsenceAsync( +@" +class A +{ + +} + +class C +{ + void M(object o) + { + switch (o) + { + case A $$ + } + } +} +"); + } + + [WorkItem(31367, "https://github.com/dotnet/roslyn/issues/31367")] + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestMissingInCaseClause2() + { + await VerifyAbsenceAsync( +@" +namespace N +{ + class A + { + + } +} + +class C +{ + void M(object o) + { + switch (o) + { + case N.A $$ + } + } +} +"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/IsKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/IsKeywordRecommenderTests.cs index 6a4e695bdc19c..a6f2fe05b8eb4 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/IsKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/IsKeywordRecommenderTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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; @@ -306,5 +304,56 @@ void M() } }"); } + + [WorkItem(31367, "https://github.com/dotnet/roslyn/issues/31367")] + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestMissingInCaseClause1() + { + await VerifyAbsenceAsync( +@" +class A +{ + +} + +class C +{ + void M(object o) + { + switch (o) + { + case A $$ + } + } +} +"); + } + + [WorkItem(31367, "https://github.com/dotnet/roslyn/issues/31367")] + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestMissingInCaseClause2() + { + await VerifyAbsenceAsync( +@" +namespace N +{ + class A + { + + } +} + +class C +{ + void M(object o) + { + switch (o) + { + case N.A $$ + } + } +} +"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/NewKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/NewKeywordRecommenderTests.cs index 05b744c17e4bd..11d964af03cac 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/NewKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/NewKeywordRecommenderTests.cs @@ -1117,5 +1117,52 @@ public async Task TestAfterRefExpression() await VerifyKeywordAsync(AddInsideMethod( @"ref int x = ref $$")); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInRawStringInterpolation_SingleLine() + { + await VerifyKeywordAsync(AddInsideMethod( +@"var x = $""""""{$$}""""""")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInRawStringInterpolation_SingleLine_MultiBrace() + { + await VerifyKeywordAsync(AddInsideMethod( +@"var x = ${|#0:|}$""""""{{$$}}""""""")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInRawStringInterpolation_SingleLineIncomplete() + { + await VerifyKeywordAsync(AddInsideMethod( +@"var x = $""""""{$$")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInRawStringInterpolation_MultiLine() + { + await VerifyKeywordAsync(AddInsideMethod( +@"var x = $"""""" +{$$} +""""""")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInRawStringInterpolation_MultiLine_MultiBrace() + { + await VerifyKeywordAsync(AddInsideMethod( +@"var x = ${|#0:|}$"""""" +{{$$}} +""""""")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInRawStringInterpolation_MultiLineIncomplete() + { + await VerifyKeywordAsync(AddInsideMethod( +@"var x = $"""""" +{$$")); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs index 8022c12ca04b1..29905b5d430f8 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs @@ -32,7 +32,7 @@ public abstract class RecommenderTests : TestBase internal async Task VerifyWorkerAsync(string markup, bool absent, CSharpParseOptions options = null, int? matchPriority = null) { - MarkupTestFile.GetPosition(markup, out var code, out int position); + Testing.TestFileMarkupParser.GetPosition(markup, out var code, out var position); await VerifyAtPositionAsync(code, position, absent, options: options, matchPriority: matchPriority); await VerifyInFrontOfCommentAsync(code, position, absent, options: options, matchPriority: matchPriority); await VerifyAtEndOfFileAsync(code, position, absent, options: options, matchPriority: matchPriority); diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/RefKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/RefKeywordRecommenderTests.cs index a8671038ddd56..7d44d5678774c 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/RefKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/RefKeywordRecommenderTests.cs @@ -977,5 +977,34 @@ await VerifyKeywordAsync( @"namespace N; $$"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + [WorkItem(58906, "https://github.com/dotnet/roslyn/issues/58906")] + public async Task TestInPotentialLambdaParamListParsedAsCastOnDifferentLines() + { + await VerifyKeywordAsync( +@"class C +{ + static void Main(string[] args) + { + var f = ($$) + Main(null); + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + [WorkItem(58906, "https://github.com/dotnet/roslyn/issues/58906")] + public async Task TestInPotentialLambdaParamListParsedAsCastOnSameLine() + { + await VerifyKeywordAsync( +@"class C +{ + static void Main(string[] args) + { + var f = ($$)Main(null); + } +}"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ReferenceKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ReferenceKeywordRecommenderTests.cs index 01df7020e3972..97327f9fee652 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ReferenceKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ReferenceKeywordRecommenderTests.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/SwitchKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/SwitchKeywordRecommenderTests.cs index c851a4e125b8e..ed7a3f8a14b47 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/SwitchKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/SwitchKeywordRecommenderTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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; @@ -250,5 +248,56 @@ void M() } }"); } + + [WorkItem(31367, "https://github.com/dotnet/roslyn/issues/31367")] + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestMissingInCaseClause1() + { + await VerifyAbsenceAsync( +@" +class A +{ + +} + +class C +{ + void M(object o) + { + switch (o) + { + case A $$ + } + } +} +"); + } + + [WorkItem(31367, "https://github.com/dotnet/roslyn/issues/31367")] + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestMissingInCaseClause2() + { + await VerifyAbsenceAsync( +@" +namespace N +{ + class A + { + + } +} + +class C +{ + void M(object o) + { + switch (o) + { + case N.A $$ + } + } +} +"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/WithKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/WithKeywordRecommenderTests.cs index d8ffab216d7af..3460c1437412c 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/WithKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/WithKeywordRecommenderTests.cs @@ -251,5 +251,56 @@ void M() } }"); } + + [WorkItem(31367, "https://github.com/dotnet/roslyn/issues/31367")] + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestMissingInCaseClause1() + { + await VerifyAbsenceAsync( +@" +class A +{ + +} + +class C +{ + void M(object o) + { + switch (o) + { + case A $$ + } + } +} +"); + } + + [WorkItem(31367, "https://github.com/dotnet/roslyn/issues/31367")] + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestMissingInCaseClause2() + { + await VerifyAbsenceAsync( +@" +namespace N +{ + class A + { + + } +} + +class C +{ + void M(object o) + { + switch (o) + { + case N.A $$ + } + } +} +"); + } } } diff --git a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindBaseSymbolsCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindBaseSymbolsCommandHandler.cs index 5e2185b61c07a..5e633f238c4c6 100644 --- a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindBaseSymbolsCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindBaseSymbolsCommandHandler.cs @@ -6,9 +6,9 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindDerivedSymbolsCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindDerivedSymbolsCommandHandler.cs index 6577d0200543a..a44978f3fc2ab 100644 --- a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindDerivedSymbolsCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindDerivedSymbolsCommandHandler.cs @@ -8,7 +8,6 @@ using System.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindSymbols; @@ -20,6 +19,7 @@ using Roslyn.Utilities; using VSCommanding = Microsoft.VisualStudio.Commanding; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.FindUsages; namespace Microsoft.CodeAnalysis.Editor.Implementation.NavigationCommandHandlers { diff --git a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindExtensionMethodsCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindExtensionMethodsCommandHandler.cs index 843a5cecea69f..1a8ec8d3d0750 100644 --- a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindExtensionMethodsCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindExtensionMethodsCommandHandler.cs @@ -9,10 +9,10 @@ using System.ComponentModel.Composition; using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindImplementingMembersCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindImplementingMembersCommandHandler.cs index 7e8998cfff489..daa41f3df2dc6 100644 --- a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindImplementingMembersCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindImplementingMembersCommandHandler.cs @@ -9,7 +9,6 @@ using System.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindUsages; diff --git a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindMemberOverloadsCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindMemberOverloadsCommandHandler.cs index 2c6ac335cf584..79a8ce4b9885b 100644 --- a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindMemberOverloadsCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindMemberOverloadsCommandHandler.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; @@ -19,6 +18,7 @@ using VSCommanding = Microsoft.VisualStudio.Commanding; using Microsoft.CodeAnalysis.Host.Mef; using System.Threading; +using Microsoft.CodeAnalysis.FindUsages; namespace Microsoft.CodeAnalysis.Editor.Implementation.NavigationCommandHandlers { diff --git a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindReferencesOfOverloadsCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindReferencesOfOverloadsCommandHandler.cs index 5006710ae5adb..24e866d4ca58f 100644 --- a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindReferencesOfOverloadsCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindReferencesOfOverloadsCommandHandler.cs @@ -10,11 +10,11 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/EditorFeatures/Core.Cocoa/Preview/PreviewPane.cs b/src/EditorFeatures/Core.Cocoa/Preview/PreviewPane.cs index 125ccb1cb72ef..b395e9abea6dd 100644 --- a/src/EditorFeatures/Core.Cocoa/Preview/PreviewPane.cs +++ b/src/EditorFeatures/Core.Cocoa/Preview/PreviewPane.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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 AppKit; @@ -15,10 +13,10 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Preview { internal class PreviewPane : NSView { - private DifferenceViewerPreview _differenceViewerPreview; - private readonly NSTextField titleField; + private DifferenceViewerPreview? _differenceViewerPreview; + private readonly NSTextField? titleField; - public PreviewPane(string id, string title, Uri helpLink, string helpLinkToolTipText, IReadOnlyList previewContent) + public PreviewPane(string? id, string? title, Uri? helpLink, string? helpLinkToolTipText, IReadOnlyList previewContent) { _differenceViewerPreview = (DifferenceViewerPreview)previewContent[0]; var view = ((ICocoaDifferenceViewer)_differenceViewerPreview.Viewer).VisualElement; @@ -102,7 +100,7 @@ public PreviewPane(IntPtr ptr) { } - private static NSAttributedString GenerateAttributeString(string id, string title, Uri link, string linkTooltip) + private static NSAttributedString? GenerateAttributeString(string? id, string? title, Uri? link, string? linkTooltip) { if (string.IsNullOrEmpty(title)) return null; diff --git a/src/EditorFeatures/Core.Cocoa/Preview/PreviewPaneService.cs b/src/EditorFeatures/Core.Cocoa/Preview/PreviewPaneService.cs index a18259c196c47..18d56f07d92ee 100644 --- a/src/EditorFeatures/Core.Cocoa/Preview/PreviewPaneService.cs +++ b/src/EditorFeatures/Core.Cocoa/Preview/PreviewPaneService.cs @@ -2,21 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Composition; -using System.Globalization; -using AppKit; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Host; -using Microsoft.CodeAnalysis.Editor.Shared; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.VisualStudio.Core.Imaging; -using Microsoft.VisualStudio.Imaging; namespace Microsoft.CodeAnalysis.Editor.Implementation.Preview { @@ -34,11 +27,10 @@ IWorkspaceService IWorkspaceServiceFactory.CreateService(HostWorkspaceServices w { return this; } - object IPreviewPaneService.GetPreviewPane(DiagnosticData data, IReadOnlyList previewContent) - { - var title = data?.Message; - if (string.IsNullOrWhiteSpace(title)) + object? IPreviewPaneService.GetPreviewPane(DiagnosticData? data, IReadOnlyList? previewContent) + { + if (data == null || string.IsNullOrWhiteSpace(data.Message)) { if (previewContent == null) { @@ -47,24 +39,22 @@ object IPreviewPaneService.GetPreviewPane(DiagnosticData data, IReadOnlyList /// UI manager for graphic overlay tags. These tags will simply paint something related to the text. /// - internal abstract class AbstractAdornmentManager where T : GraphicsTag + internal abstract class AbstractAdornmentManager where T : BrushTag { private readonly object _invalidatedSpansLock = new(); @@ -251,7 +251,7 @@ protected void UpdateSpans_CallOnlyOnUIThread(NormalizedSnapshotSpanCollection c AddAdornmentsToAdornmentLayer_CallOnlyOnUIThread(changedSpanCollection); } - protected bool ShouldDrawTag(SnapshotSpan snapshotSpan, IMappingTagSpan mappingTagSpan, out SnapshotPoint mappedPoint) + protected bool ShouldDrawTag(SnapshotSpan snapshotSpan, IMappingTagSpan mappingTagSpan, out SnapshotPoint mappedPoint) { mappedPoint = default; var point = GetMappedPoint(snapshotSpan, mappingTagSpan); @@ -275,7 +275,7 @@ protected bool ShouldDrawTag(SnapshotSpan snapshotSpan, IMappingTagSpan mappingTagSpan) + protected SnapshotPoint? GetMappedPoint(SnapshotSpan snapshotSpan, IMappingTagSpan mappingTagSpan) { var point = mappingTagSpan.Span.Start.GetPoint(snapshotSpan.Snapshot, PositionAffinity.Predecessor); if (point == null) diff --git a/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManagerProvider.cs b/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManagerProvider.cs index 84d9057cf591d..33b7d80445a14 100644 --- a/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManagerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManagerProvider.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Adornments { internal abstract class AbstractAdornmentManagerProvider : IWpfTextViewCreationListener - where TTag : GraphicsTag + where TTag : BrushTag { protected readonly IThreadingContext ThreadingContext; protected readonly IViewTagAggregatorFactoryService TagAggregatorFactoryService; diff --git a/src/EditorFeatures/Core.Wpf/Adornments/BrushTag.cs b/src/EditorFeatures/Core.Wpf/Adornments/BrushTag.cs new file mode 100644 index 0000000000000..bc80ee2c1f2ce --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Adornments/BrushTag.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.Windows; +using System.Windows.Media; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Tagging; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.Adornments +{ + /// + /// Base type for tags that want to draw something with a simple configurable color. What is drawn will actually be + /// the responsibility of the particular subclass. Tags that want to draw + /// just a simple single should subclass . In that case the will just defer to the tag itself to create the element rather than + /// computing it itself. + /// + internal abstract class BrushTag : ITag + { + private static readonly Color s_lightGray = Color.FromRgb(0xA5, 0xA5, 0xA5); + private readonly IEditorFormatMap _editorFormatMap; + + private Brush? _brush; + + protected BrushTag(IEditorFormatMap editorFormatMap) + => _editorFormatMap = editorFormatMap; + + public Brush GetBrush(IWpfTextView view) + // If we can't get the color for some reason, fall back to a hard-coded value the editor has for outlining. + => _brush ??= new SolidColorBrush(this.GetColor(view, _editorFormatMap) ?? s_lightGray); + + protected abstract Color? GetColor(IWpfTextView view, IEditorFormatMap editorFormatMap); + } +} diff --git a/src/EditorFeatures/Core.Wpf/Adornments/GraphicsResult.cs b/src/EditorFeatures/Core.Wpf/Adornments/GraphicsResult.cs index 64ff7a1318d8e..826c7fb5ba504 100644 --- a/src/EditorFeatures/Core.Wpf/Adornments/GraphicsResult.cs +++ b/src/EditorFeatures/Core.Wpf/Adornments/GraphicsResult.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. -#nullable disable - using System; +using System.Threading; using System.Windows; namespace Microsoft.CodeAnalysis.Editor.Implementation.Adornments @@ -12,22 +11,15 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Adornments internal class GraphicsResult : IDisposable { public UIElement VisualElement { get; } - private Action _dispose; + private Action? _dispose; - public GraphicsResult(UIElement visualElement, Action dispose) + public GraphicsResult(UIElement visualElement, Action? dispose) { VisualElement = visualElement; _dispose = dispose; } public void Dispose() - { - if (_dispose != null) - { - _dispose(); - - _dispose = null; - } - } + => Interlocked.Exchange(ref _dispose, null)?.Invoke(); } } diff --git a/src/EditorFeatures/Core.Wpf/Adornments/GraphicsTag.cs b/src/EditorFeatures/Core.Wpf/Adornments/GraphicsTag.cs index 79c77bae7b240..2fefccadc14a6 100644 --- a/src/EditorFeatures/Core.Wpf/Adornments/GraphicsTag.cs +++ b/src/EditorFeatures/Core.Wpf/Adornments/GraphicsTag.cs @@ -2,47 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Windows.Media; using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Formatting; -using Microsoft.VisualStudio.Text.Tagging; namespace Microsoft.CodeAnalysis.Editor.Implementation.Adornments { - /// - /// This needs to be public for testing the AdornmentManager - /// - internal abstract class GraphicsTag : ITag + internal abstract class GraphicsTag : BrushTag { - private readonly IEditorFormatMap _editorFormatMap; - protected Brush _graphicsTagBrush; - protected Color _graphicsTagColor; - - protected GraphicsTag(IEditorFormatMap editorFormatMap) - => _editorFormatMap = editorFormatMap; - - protected virtual void Initialize(IWpfTextView view) + protected GraphicsTag(IEditorFormatMap editorFormatMap) : base(editorFormatMap) { - if (_graphicsTagBrush != null) - { - return; - } - - // If we can't get the color for some reason, fall back to a hardcoded value - // the editor has for outlining. - var lightGray = Color.FromRgb(0xA5, 0xA5, 0xA5); - - var color = this.GetColor(view, _editorFormatMap) ?? lightGray; - - _graphicsTagColor = color; - _graphicsTagBrush = new SolidColorBrush(_graphicsTagColor); } - protected abstract Color? GetColor(IWpfTextView view, IEditorFormatMap editorFormatMap); - /// /// This method allows corresponding adornment manager to ask for a graphical glyph. /// diff --git a/src/EditorFeatures/Core.Wpf/Classification/ClassificationTypeFormatDefinitions.cs b/src/EditorFeatures/Core.Wpf/Classification/ClassificationTypeFormatDefinitions.cs index 3192da5d32069..b63b3b4f71be8 100644 --- a/src/EditorFeatures/Core.Wpf/Classification/ClassificationTypeFormatDefinitions.cs +++ b/src/EditorFeatures/Core.Wpf/Classification/ClassificationTypeFormatDefinitions.cs @@ -900,6 +900,164 @@ public RegexOtherEscapeFormatDefinition() } #endregion + #region JSON + + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonComment)] + [Name(ClassificationTypeNames.JsonComment)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonCommentFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonCommentFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Comment; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonNumber)] + [Name(ClassificationTypeNames.JsonNumber)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonNumberFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonNumberFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Number; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonString)] + [Name(ClassificationTypeNames.JsonString)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonStringFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonStringFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_String; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonKeyword)] + [Name(ClassificationTypeNames.JsonKeyword)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonKeywordFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonKeywordFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Keyword; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonText)] + [Name(ClassificationTypeNames.JsonText)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonTextFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonTextFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Text; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonOperator)] + [Name(ClassificationTypeNames.JsonOperator)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonOperatorFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonOperatorFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Operator; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonPunctuation)] + [Name(ClassificationTypeNames.JsonPunctuation)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonPunctuationFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonPunctuationFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Punctuation; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonObject)] + [Name(ClassificationTypeNames.JsonObject)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonObjectFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonObjectFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Object; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonArray)] + [Name(ClassificationTypeNames.JsonArray)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonArrayFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonArrayFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Array; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonPropertyName)] + [Name(ClassificationTypeNames.JsonPropertyName)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonPropertyNameFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonPropertyNameFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Property_Name; + } + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.JsonConstructorName)] + [Name(ClassificationTypeNames.JsonConstructorName)] + [Order(After = ClassificationTypeNames.StringLiteral)] + [Order(After = ClassificationTypeNames.VerbatimStringLiteral)] + [UserVisible(true)] + [ExcludeFromCodeCoverage] + private class JsonConstructorNameFormatDefinition : ClassificationFormatDefinition + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonConstructorNameFormatDefinition() + => this.DisplayName = EditorFeaturesResources.JSON_in_string_literal_Constructor_Name; + } + #endregion + #region VB XML Literals - Attribute Name [Export(typeof(EditorFormatDefinition))] [ClassificationType(ClassificationTypeNames = ClassificationTypeNames.XmlLiteralAttributeName)] diff --git a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs index 15a73fdeb0fee..0b3582b3f6a5e 100644 --- a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs +++ b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs @@ -169,11 +169,12 @@ Run GetRunForId(out Hyperlink? link) var id = new Run(_diagnostic.Id); link = null; - if (!string.IsNullOrEmpty(_diagnostic.HelpLink)) + var helpLinkUri = _diagnostic.GetValidHelpLinkUri(); + if (helpLinkUri != null) { link = new Hyperlink(id) { - NavigateUri = new Uri(_diagnostic.HelpLink), + NavigateUri = helpLinkUri }; } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/Dashboard/DashboardViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/Dashboard/DashboardViewModel.cs index 5007ba39ce57e..9578fd2a2fcc8 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/Dashboard/DashboardViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/Dashboard/DashboardViewModel.cs @@ -10,44 +10,27 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Windows; -using Microsoft.CodeAnalysis.Rename; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.InlineRename; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { internal class DashboardViewModel : INotifyPropertyChanged, IDisposable { - private readonly Visibility _renameOverloadsVisibility; - - private DashboardSeverity _severity = DashboardSeverity.None; private readonly InlineRenameSession _session; + private DashboardSeverity _severity = DashboardSeverity.None; private string _searchText; private int _resolvableConflictCount; private int _unresolvableConflictCount; private string _errorText; - private bool _defaultRenameOverloadFlag; - private readonly bool _isRenameOverloadsEditable; - private bool _defaultRenameInStringsFlag; - private bool _defaultRenameInCommentsFlag; - private bool _defaultRenameFileFlag; - private bool _defaultPreviewChangesFlag; private bool _isReplacementTextValid; public DashboardViewModel(InlineRenameSession session) { - Contract.ThrowIfNull(session); _session = session; _searchText = EditorFeaturesResources.Searching; - _renameOverloadsVisibility = session.HasRenameOverloads ? Visibility.Visible : Visibility.Collapsed; - _isRenameOverloadsEditable = !session.ForceRenameOverloads; - - _defaultRenameOverloadFlag = session.OptionSet.GetOption(RenameOptions.RenameOverloads) || session.ForceRenameOverloads; - _defaultRenameInStringsFlag = session.OptionSet.GetOption(RenameOptions.RenameInStrings); - _defaultRenameInCommentsFlag = session.OptionSet.GetOption(RenameOptions.RenameInComments); - _defaultPreviewChangesFlag = session.OptionSet.GetOption(RenameOptions.PreviewChanges); - _session.ReferenceLocationsChanged += OnReferenceLocationsChanged; _session.ReplacementsComputed += OnReplacementsComputed; _session.ReplacementTextChanged += OnReplacementTextChanged; @@ -82,8 +65,7 @@ private void OnIsReplacementTextValidChanged(bool isReplacementTextValid) private void ComputeDefaultRenameFileFlag() { // If replacementText is invalid, we won't rename the file. - DefaultRenameFileFlag = _isReplacementTextValid - && (_session.OptionSet.GetOption(RenameOptions.RenameFile) || AllowFileRename); + DefaultRenameFileFlag = _isReplacementTextValid && AllowFileRename && _session.Options.RenameFile; } private void OnReplacementsComputed(object sender, IInlineRenameReplacementInfo result) @@ -249,82 +231,70 @@ public string UnresolvableConflictText } public bool HasError - { - get { return _errorText != null; } - } + => _errorText != null; public string ErrorText => _errorText; - public Visibility RenameOverloadsVisibility => _renameOverloadsVisibility; + public Visibility RenameOverloadsVisibility + => _session.HasRenameOverloads ? Visibility.Visible : Visibility.Collapsed; - public bool IsRenameOverloadsEditable => _isRenameOverloadsEditable; + public bool IsRenameOverloadsEditable + => !_session.MustRenameOverloads; public bool DefaultRenameOverloadFlag { - get - { - return _defaultRenameOverloadFlag; - } + get => _session.Options.RenameOverloads; set { if (IsRenameOverloadsEditable) { - _defaultRenameOverloadFlag = value; - _session.RefreshRenameSessionWithOptionsChanged(RenameOptions.RenameOverloads, value); + _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameOverloads), value); + _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameOverloads = value }); } } } public bool DefaultRenameInStringsFlag { - get - { - return _defaultRenameInStringsFlag; - } + get => _session.Options.RenameInStrings; set { - _defaultRenameInStringsFlag = value; - _session.RefreshRenameSessionWithOptionsChanged(RenameOptions.RenameInStrings, value); + _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameInStrings), value); + _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInStrings = value }); } } public bool DefaultRenameInCommentsFlag { - get - { - return _defaultRenameInCommentsFlag; - } + get => _session.Options.RenameInComments; set { - _defaultRenameInCommentsFlag = value; - _session.RefreshRenameSessionWithOptionsChanged(RenameOptions.RenameInComments, value); + _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameInComments), value); + _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInComments = value }); } } public bool DefaultRenameFileFlag { - get => _defaultRenameFileFlag; + get => _session.Options.RenameFile; set { - _defaultRenameFileFlag = value; - _session.RefreshRenameSessionWithOptionsChanged(RenameOptions.RenameFile, value); + _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameFile), value); + _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameFile = value }); } } public bool DefaultPreviewChangesFlag { - get - { - return _defaultPreviewChangesFlag; - } + get => _session.PreviewChanges; set { - _defaultPreviewChangesFlag = value; - _session.RefreshRenameSessionWithOptionsChanged(RenameOptions.PreviewChanges, value); + _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.PreviewChanges), value); + _session.SetPreviewChanges(value); } } diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs index caaa90791ad6a..041b4a2452056 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs @@ -44,13 +44,13 @@ public bool CanNavigateToLineAndOffset(Workspace workspace, DocumentId documentI public bool CanNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, CancellationToken cancellationToken) => false; - public async Task TryNavigateToSpanAsync(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet? options, bool allowInvalidSpan, CancellationToken cancellationToken) + public async Task TryNavigateToSpanAsync(Workspace workspace, DocumentId documentId, TextSpan textSpan, NavigationOptions options, bool allowInvalidSpan, CancellationToken cancellationToken) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); return TryNavigateToSpan(workspace, documentId, textSpan, options, allowInvalidSpan, cancellationToken); } - public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet? options, bool allowInvalidSpan, CancellationToken cancellationToken) + public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, NavigationOptions options, bool allowInvalidSpan, CancellationToken cancellationToken) { if (workspace is not InteractiveWindowWorkspace interactiveWorkspace) { @@ -95,10 +95,10 @@ public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSp return true; } - public bool TryNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset, OptionSet? options, CancellationToken cancellationToken) + public bool TryNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset, NavigationOptions options, CancellationToken cancellationToken) => throw new NotSupportedException(); - public bool TryNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, OptionSet? options, CancellationToken cancellationToken) + public bool TryNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, NavigationOptions options, CancellationToken cancellationToken) => throw new NotSupportedException(); } } diff --git a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManagerProvider.cs b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManagerProvider.cs index c089982b37298..d9bdabc316fc8 100644 --- a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManagerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManagerProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Editor.Implementation.Adornments; @@ -35,7 +33,7 @@ internal class LineSeparatorAdornmentManagerProvider : [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Squiggle)] #pragma warning disable 0169 #pragma warning disable IDE0051 // Remove unused private members - private readonly AdornmentLayerDefinition _lineSeparatorLayer; + private readonly AdornmentLayerDefinition? _lineSeparatorLayer; #pragma warning restore IDE0051 // Remove unused private members #pragma warning restore 0169 diff --git a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTag.cs b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTag.cs index a3f85f0e6015f..232c2ff17dced 100644 --- a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTag.cs +++ b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTag.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Windows; using System.Windows.Controls; @@ -35,24 +33,17 @@ public LineSeparatorTag(IEditorFormatMap editorFormatMap) /// /// Creates a very long line at the bottom of bounds. /// - public override GraphicsResult GetGraphics(IWpfTextView view, Geometry bounds, TextFormattingRunProperties format) + public override GraphicsResult GetGraphics(IWpfTextView view, Geometry bounds, TextFormattingRunProperties? format) { - Initialize(view); - var border = new Border() { - BorderBrush = _graphicsTagBrush, + BorderBrush = GetBrush(view), BorderThickness = new Thickness(0, 0, 0, bottom: 1), Height = 1, Width = view.ViewportWidth }; - void viewportWidthChangedHandler(object s, EventArgs e) - { - border.Width = view.ViewportWidth; - } - - view.ViewportWidthChanged += viewportWidthChangedHandler; + view.ViewportWidthChanged += ViewportWidthChangedHandler; // Subtract rect.Height to ensure that the line separator is drawn // at the bottom of the line, rather than immediately below. @@ -60,7 +51,12 @@ void viewportWidthChangedHandler(object s, EventArgs e) Canvas.SetTop(border, bounds.Bounds.Bottom - border.Height); return new GraphicsResult(border, - () => view.ViewportWidthChanged -= viewportWidthChangedHandler); + () => view.ViewportWidthChanged -= ViewportWidthChangedHandler); + + void ViewportWidthChangedHandler(object s, EventArgs e) + { + border.Width = view.ViewportWidth; + } } } } diff --git a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs index 17fbcbe0b569c..b115f5b819240 100644 --- a/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs @@ -2,13 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Implementation.Tagging; +using Microsoft.CodeAnalysis.Editor.LineSeparators; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.LineSeparators; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -83,32 +84,32 @@ protected override async Task ProduceTagsAsync( { var document = documentSnapshotSpan.Document; if (document == null) - { return; - } if (!GlobalOptions.GetOption(FeatureOnOffOptions.LineSeparator, document.Project.Language)) - { return; - } - - LineSeparatorTag tag; - lock (_lineSeperatorTagGate) - { - tag = _lineSeparatorTag; - } using (Logger.LogBlock(FunctionId.Tagger_LineSeparator_TagProducer_ProduceTags, cancellationToken)) { var snapshotSpan = documentSnapshotSpan.SnapshotSpan; var lineSeparatorService = document.GetLanguageService(); + if (lineSeparatorService == null) + return; + var lineSeparatorSpans = await lineSeparatorService.GetLineSeparatorsAsync(document, snapshotSpan.Span.ToTextSpan(), cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - foreach (var span in lineSeparatorSpans) + if (lineSeparatorSpans.Length == 0) + return; + + LineSeparatorTag tag; + lock (_lineSeperatorTagGate) { - context.AddTag(new TagSpan(span.ToSnapshotSpan(snapshotSpan.Snapshot), tag)); + tag = _lineSeparatorTag; } + + foreach (var span in lineSeparatorSpans) + context.AddTag(new TagSpan(span.ToSnapshotSpan(snapshotSpan.Snapshot), tag)); } } } diff --git a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs index 77466cd692963..294f8ff7b0a72 100644 --- a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs +++ b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs @@ -116,7 +116,7 @@ public void NavigateTo() workspace, document.Id, _searchResult.NavigableItem.SourceSpan, - options: null, + NavigationOptions.Default, allowInvalidSpan: _searchResult.NavigableItem.IsStale, CancellationToken.None); } diff --git a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs index 1cb6846ff49e2..08ba4018943c4 100644 --- a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs +++ b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs @@ -6,7 +6,9 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.NavigateTo; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -112,7 +114,7 @@ private void StartSearch(INavigateToCallback callback, string searchValue, IImmu kinds, _threadingContext.DisposalToken); - _ = searcher.SearchAsync(searchCurrentDocument, _cancellationTokenSource.Token); + _ = searcher.SearchAsync(searchCurrentDocument, _cancellationTokenSource.Token).ReportNonFatalErrorUnlessCancelledAsync(_cancellationTokenSource.Token); } } } diff --git a/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs b/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs index 69ca77fee9df4..a1344ec44efd0 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs @@ -84,7 +84,7 @@ public void FindResults(string relationshipName, IPeekResultCollection resultCol foreach (var declaration in sourceLocations) { - var declarationLocation = declaration.GetLineSpan(); + var declarationLocation = declaration.GetMappedLineSpan(); var entityOfInterestSpan = PeekHelpers.GetEntityOfInterestSpan(symbol, workspace, declaration, cancellationToken); resultCollection.Add(PeekHelpers.CreateDocumentPeekResult(declarationLocation.Path, declarationLocation.Span, entityOfInterestSpan, _peekableItem.PeekResultFactory)); diff --git a/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs b/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs index 8e1a1b20f067a..0efa3aaeea75d 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs @@ -67,7 +67,7 @@ internal static LinePositionSpan GetEntityOfInterestSpan(ISymbol symbol, Workspa break; } - return identifierLocation.SourceTree.GetLocation(node.Span).GetLineSpan().Span; + return identifierLocation.SourceTree.GetLocation(node.Span).GetMappedLineSpan().Span; } } } diff --git a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs index 36fa4dc03229c..e08c1e75f5c1a 100644 --- a/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs +++ b/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs @@ -10,13 +10,12 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Peek; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Navigation; -using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Language.Intellisense; namespace Microsoft.CodeAnalysis.Editor.Implementation.Peek diff --git a/src/EditorFeatures/Core.Wpf/PublicAPI.Shipped.txt b/src/EditorFeatures/Core.Wpf/PublicAPI.Shipped.txt index e69de29bb2d1d..8b581ef31f58f 100644 --- a/src/EditorFeatures/Core.Wpf/PublicAPI.Shipped.txt +++ b/src/EditorFeatures/Core.Wpf/PublicAPI.Shipped.txt @@ -0,0 +1,2 @@ +Microsoft.CodeAnalysis.Editor.Peek.IPeekableItemFactory +Microsoft.CodeAnalysis.Editor.Peek.IPeekableItemFactory.GetPeekableItemsAsync(Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Project project, Microsoft.VisualStudio.Language.Intellisense.IPeekResultFactory peekResultFactory, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task> diff --git a/src/EditorFeatures/Core.Wpf/PublicAPI.Unshipped.txt b/src/EditorFeatures/Core.Wpf/PublicAPI.Unshipped.txt index 8b581ef31f58f..8b137891791fe 100644 --- a/src/EditorFeatures/Core.Wpf/PublicAPI.Unshipped.txt +++ b/src/EditorFeatures/Core.Wpf/PublicAPI.Unshipped.txt @@ -1,2 +1 @@ -Microsoft.CodeAnalysis.Editor.Peek.IPeekableItemFactory -Microsoft.CodeAnalysis.Editor.Peek.IPeekableItemFactory.GetPeekableItemsAsync(Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Project project, Microsoft.VisualStudio.Language.Intellisense.IPeekResultFactory peekResultFactory, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task> + diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs index d317fb8f92c13..c1c72eafde77f 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs @@ -5,17 +5,15 @@ #nullable disable using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; @@ -86,7 +84,7 @@ private async Task ComputeModelInBackgroundAsync( } } - var options = SignatureHelpOptions.From(document.Project); + var options = Controller.GlobalOptions.GetSignatureHelpOptions(document.Project.Language); // first try to query the providers that can trigger on the specified character var (provider, items) = await ComputeItemsAsync( diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs index caf0be65a6d97..b850b8afd6c9f 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; @@ -37,6 +38,7 @@ internal partial class Controller : public string DisplayName => EditorFeaturesResources.Signature_Help; public Controller( + IGlobalOptionService globalOptions, IThreadingContext threadingContext, ITextView textView, ITextBuffer subjectBuffer, @@ -45,7 +47,7 @@ public Controller( IDocumentProvider documentProvider, IList> allProviders, IAsyncCompletionBroker completionBroker) - : base(threadingContext, textView, subjectBuffer, presenter, asyncListener, documentProvider, "SignatureHelp") + : base(globalOptions, threadingContext, textView, subjectBuffer, presenter, asyncListener, documentProvider, "SignatureHelp") { _completionBroker = completionBroker; _allProviders = allProviders; @@ -53,6 +55,7 @@ public Controller( // For testing purposes. internal Controller( + IGlobalOptionService globalOptions, IThreadingContext threadingContext, ITextView textView, ITextBuffer subjectBuffer, @@ -61,7 +64,7 @@ internal Controller( IDocumentProvider documentProvider, IList providers, IAsyncCompletionBroker completionBroker) - : base(threadingContext, textView, subjectBuffer, presenter, asyncListener, documentProvider, "SignatureHelp") + : base(globalOptions, threadingContext, textView, subjectBuffer, presenter, asyncListener, documentProvider, "SignatureHelp") { _providers = providers.ToImmutableArray(); _completionBroker = completionBroker; diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpControllerProvider.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpControllerProvider.cs index 2d0c25db4019e..3f29cbce1ae38 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpControllerProvider.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpControllerProvider.cs @@ -8,6 +8,7 @@ using System.Linq; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -25,6 +26,7 @@ internal class SignatureHelpControllerProvider : ForegroundThreadAffinitizedObje { private static readonly object s_controllerPropertyKey = new(); + private readonly IGlobalOptionService _globalOptions; private readonly IIntelliSensePresenter _signatureHelpPresenter; private readonly IAsynchronousOperationListener _listener; private readonly IAsyncCompletionBroker _completionBroker; @@ -33,6 +35,7 @@ internal class SignatureHelpControllerProvider : ForegroundThreadAffinitizedObje [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public SignatureHelpControllerProvider( + IGlobalOptionService globalOptions, IThreadingContext threadingContext, [ImportMany] IEnumerable> signatureHelpProviders, [ImportMany] IEnumerable, OrderableMetadata>> signatureHelpPresenters, @@ -40,6 +43,7 @@ public SignatureHelpControllerProvider( IAsynchronousOperationListenerProvider listenerProvider) : base(threadingContext) { + _globalOptions = globalOptions; _signatureHelpPresenter = ExtensionOrderer.Order(signatureHelpPresenters).Select(lazy => lazy.Value).FirstOrDefault(); _listener = listenerProvider.GetListener(FeatureAttribute.SignatureHelp); _completionBroker = completionBroker; @@ -70,6 +74,7 @@ private Controller GetControllerSlow(ITextView textView, ITextBuffer subjectBuff subjectBuffer, s_controllerPropertyKey, (textView, subjectBuffer) => new Controller( + _globalOptions, ThreadingContext, textView, subjectBuffer, diff --git a/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.VisibleBlock.cs b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.VisibleBlock.cs new file mode 100644 index 0000000000000..d7deaeeef5cce --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.VisibleBlock.cs @@ -0,0 +1,179 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Formatting; + +namespace Microsoft.CodeAnalysis.Editor.StringIndentation +{ + internal partial class StringIndentationAdornmentManager + { + /// + /// Represents the X position of the vertical line we're drawing, and the chunks of that vertical line if we + /// need to break it up (for example if we need to jump past interpolation holes). + /// + /// Forked from https://devdiv.visualstudio.com/DevDiv/_git/VS-Platform?path=/src/Editor/Text/Impl/Structure/VisibleBlock.cs + /// + private readonly struct VisibleBlock + { + public readonly double X; + public readonly ImmutableArray<(double start, double end)> YSegments; + + private VisibleBlock(double x, ImmutableArray<(double start, double end)> ySegments) + { + X = x; + YSegments = ySegments; + } + + public static VisibleBlock? CreateVisibleBlock( + SnapshotSpan span, ImmutableArray orderedHoleSpans, IWpfTextView view) + { + // This method assumes that we've already been mapped to the view's snapshot. + Debug.Assert(span.Snapshot == view.TextSnapshot); + + // While editing (for example, deleting all the whitespace before the final quotes) the indentation line + // may move to the 0 column (temporarily until we compute the updated tags and realize this tag needs to + // go). Don't try to draw the line here as moving the line back by one will place it at the end of the + // previous line (which will cause a very distracting visual glitch). + if (span.End.GetContainingLine().Start == span.End) + return null; + + // We want to draw the line right before the quote character. So -1 to get that character's position. + // Horizontally position the adornment in the center of the character. This position could actually be + // 0 if the entire doc is deleted and we haven't recomputed the updated tags yet. So be resilient for + // the position being out of bounds. + if (span.End == 0) + return null; + + var bufferPosition = span.End - 1; + var anchorPointLine = view.GetTextViewLineContainingBufferPosition(bufferPosition); + var bounds = anchorPointLine.GetCharacterBounds(bufferPosition); + var x = Math.Floor((bounds.Left + bounds.Right) * 0.5); + + var firstLine = view.TextViewLines.FirstVisibleLine; + var lastLine = view.TextViewLines.LastVisibleLine; + + // Bug #557472: When performing a layout while scrolling downwards, the editor can occasionally + // invalidate spans that are not visible. When we ask for the start and end point for adornments, + // if the TextViewLinesCollection doesn't contain the start or end point of the GuideLineSpan, we + // usually assume that it's the top of the first visible line, or the bottom of the last visible + // line, respectively. If the editor invalidates an invisible span, this can result in an erroneous + // top to bottom adornment. + var guideLineSpanStart = span.Start; + var guideLineSpanEnd = span.End; + + if ((guideLineSpanStart > lastLine.End) || + (guideLineSpanEnd < firstLine.Start)) + { + return null; + } + + var guideLineTopLine = view.TextViewLines.GetTextViewLineContainingBufferPosition(guideLineSpanStart); + var guideLineBottomLine = view.TextViewLines.GetTextViewLineContainingBufferPosition(guideLineSpanEnd); + + // This is slightly subtle. First, the line might start on a line that is above/below what the actual + // view is displaying. In that case we want to draw up to the boundary of the view to make it look like + // the line is correctly going past that to wherever it starts/ends at. + // + // Second, the span we are working with actually includes the lines containing the delimiters of the + // string literal (since those are the only lines we're certain we have content we can snap the line + // to). But we don't want the vertical line to actually be drawn into those lines. So if those lines + // are visible, we draw at the interior border of them so that the vertical-line does not intrude into + // them. + var yTop = guideLineTopLine == null ? firstLine.Top : guideLineTopLine.Bottom; + var yBottom = guideLineBottomLine == null ? lastLine.Bottom : guideLineBottomLine.Top; + + // Now that we have the 'x' coordinate of hte vertical line, and the top/bottom points we want to draw + // it through, actually create line segments to draw. We have segments in case there are gaps in the + // line we don't want to draw (for example, for a hole). + return new VisibleBlock(x, CreateVisibleSegments(view.TextViewLines, span, orderedHoleSpans, x, yTop, yBottom)); + } + + /// + /// Given the horizontal position and the to draw the + /// vertical line through, create a set of vertical chunks to actually draw. Multiple chunks happen when we + /// have interpolation holes we have to skip over. + /// + private static ImmutableArray<(double start, double end)> CreateVisibleSegments( + ITextViewLineCollection linesCollection, + SnapshotSpan extent, + ImmutableArray orderedHoleSpans, + double x, + double yTop, + double yBottom) + { + using var _ = ArrayBuilder<(double start, double end)>.GetInstance(out var segments); + + // MinLineHeight must always be larger than ContinuationPadding so that no segments + // are created for vertical spans between lines. + const double MinLineHeight = 2.1; + const double ContinuationPadding = 2.0; + + // Find the lines in Block's extent that are currently visible. + // TODO: can we eliminate or reuse the allocation for this list? + var visibleSpanTextViewLinesCollection = linesCollection.GetTextViewLinesIntersectingSpan(extent); + + var currentSegmentTop = yTop; + var currentSegmentBottom = 0.0; + + // Iterate the visible lines of the Block's extent. + for (var i = 0; i < visibleSpanTextViewLinesCollection.Count; i++) + { + var line = visibleSpanTextViewLinesCollection[i]; + var intersectingCharSnapshotPoint = line.GetBufferPositionFromXCoordinate(x); + + // Three main cases for IntersectsNonWhitespaceChar: + // A) SV intersects a non-whitespace character. In this case we terminate + // the current segment and start the next segment at the top of the following + // line so that the segment does not intersect with text. + // B) Current line is the last visible line and is not a non-whitespace character + // so we terminate the current segment at the bottom of the last visible line + // to ensure that lines with an end-point that is not visible are still drawn. + // C) Line is not last line and does not have non-whitespace intersecting the SV + // so we continue the current segment. + // + // Also, if the line would go through an interpolation hole we want to skip it as well. + if (IntersectsNonWhitespaceChar(intersectingCharSnapshotPoint) || IsInHole(orderedHoleSpans, line)) + { + currentSegmentBottom = line.Top; + + // Only add the structure visualizer adornment line segment if it spans at least + // a few pixels in height so we don't have artifacts between lines of intersecting + // text. + if ((currentSegmentBottom - currentSegmentTop) >= MinLineHeight) + segments.Add((currentSegmentTop, currentSegmentBottom)); + + currentSegmentTop = line.Bottom + ContinuationPadding; + } + } + + // Due to mapping between versions of the Snapshots, visibleSpanTextViewLinesCollection + // may include more lines than are actually in the block, so end at yBottom. + currentSegmentBottom = yBottom; + + // Only add the structure visualizer adornment line segment if it spans at least + // an entire line in height so we don't have 1 to 3 pixel artifacts between lines + // of intersecting text. + if ((currentSegmentBottom - currentSegmentTop) >= MinLineHeight) + segments.Add((currentSegmentTop, currentSegmentBottom)); + + return segments.ToImmutable(); + } + + private static bool IsInHole(ImmutableArray orderedHoleSpans, ITextViewLine line) + => orderedHoleSpans.BinarySearch( + line.Start.Position, + (ss, pos) => pos < ss.Start ? 1 : ss.Span.Contains(pos) ? 0 : -1) >= 0; + + private static bool IntersectsNonWhitespaceChar(SnapshotPoint? intersectingCharSnapshotPoint) + => intersectingCharSnapshotPoint != null && + !char.IsWhiteSpace(intersectingCharSnapshotPoint.Value.GetChar()); + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.cs b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.cs new file mode 100644 index 0000000000000..28d2f94578765 --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.cs @@ -0,0 +1,120 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Windows.Shapes; +using Microsoft.CodeAnalysis.Editor.Implementation.Adornments; +using Microsoft.CodeAnalysis.Editor.Implementation.StringIndentation; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Tagging; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.StringIndentation +{ + internal partial class StringIndentationAdornmentManager : AbstractAdornmentManager + { + public StringIndentationAdornmentManager( + IThreadingContext threadingContext, + IWpfTextView textView, + IViewTagAggregatorFactoryService tagAggregatorFactoryService, + IAsynchronousOperationListener asyncListener, + string adornmentLayerName) + : base(threadingContext, textView, tagAggregatorFactoryService, asyncListener, adornmentLayerName) + { + } + + protected override void AddAdornmentsToAdornmentLayer_CallOnlyOnUIThread(NormalizedSnapshotSpanCollection changedSpanCollection) + { + // this method should only run on UI thread as we do WPF here. + Contract.ThrowIfFalse(TextView.VisualElement.Dispatcher.CheckAccess()); + + var viewSnapshot = TextView.TextSnapshot; + var viewLines = TextView.TextViewLines; + + foreach (var changedSpan in changedSpanCollection) + { + if (!viewLines.IntersectsBufferSpan(changedSpan)) + continue; + + var tagSpans = TagAggregator.GetTags(changedSpan); + foreach (var tagMappingSpan in tagSpans) + { + if (!ShouldDrawTag(changedSpan, tagMappingSpan, out _)) + continue; + + if (!TryMapToSingleSnapshotSpan(tagMappingSpan.Span, TextView.TextSnapshot, out var span)) + continue; + + if (!TryMapHoleSpans(tagMappingSpan.Tag.OrderedHoleSpans, out var orderedHoleSpans)) + continue; + + if (VisibleBlock.CreateVisibleBlock(span, orderedHoleSpans, TextView) is not VisibleBlock block) + continue; + + var tag = tagMappingSpan.Tag; + var brush = tag.GetBrush(TextView); + + foreach (var (start, end) in block.YSegments) + { + var line = new Line + { + SnapsToDevicePixels = true, + StrokeThickness = 1.0, + X1 = block.X, + X2 = block.X, + Y1 = start, + Y2 = end, + Stroke = brush, + }; + + AdornmentLayer.AddAdornment( + behavior: AdornmentPositioningBehavior.TextRelative, + visualSpan: span, + tag: block, + adornment: line, + removedCallback: delegate { }); + } + } + } + } + + private bool TryMapHoleSpans( + ImmutableArray spans, + out ImmutableArray result) + { + using var _ = ArrayBuilder.GetInstance(out var builder); + foreach (var span in spans) + { + var mapped = MapUpToView(TextView, span); + if (mapped == null) + { + result = default; + return false; + } + + builder.Add(mapped.Value); + } + + result = builder.ToImmutable(); + return true; + } + + private static SnapshotSpan? MapUpToView(ITextView textView, SnapshotSpan span) + { + // Must be called from the UI thread. + var start = textView.GetPositionInView(span.Start); + var end = textView.GetPositionInView(span.End); + + if (start == null || end == null || end < start) + return null; + + return new SnapshotSpan(start.Value, end.Value); + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManagerProvider.cs b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManagerProvider.cs new file mode 100644 index 0000000000000..6f971ae5424ec --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManagerProvider.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Editor.Implementation.Adornments; +using Microsoft.CodeAnalysis.Editor.StringIndentation; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.StringIndentation +{ + /// + /// This factory is called to create the view service that will manage the indentation line for raw strings. + /// + [Export(typeof(IWpfTextViewCreationListener))] + [ContentType(ContentTypeNames.RoslynContentType)] + [TextViewRole(PredefinedTextViewRoles.Document)] + internal class StringIndentationAdornmentManagerProvider : + AbstractAdornmentManagerProvider + { + private const string LayerName = "RoslynStringIndentation"; + + [Export] + [Name(LayerName)] + [ContentType(ContentTypeNames.RoslynContentType)] + [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Squiggle)] +#pragma warning disable 0169 +#pragma warning disable IDE0051 // Remove unused private members + private readonly AdornmentLayerDefinition? _stringIndentationLayer; +#pragma warning restore IDE0051 // Remove unused private members +#pragma warning restore 0169 + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public StringIndentationAdornmentManagerProvider( + IThreadingContext threadingContext, + IViewTagAggregatorFactoryService tagAggregatorFactoryService, + IGlobalOptionService globalOptions, + IAsynchronousOperationListenerProvider listenerProvider) + : base(threadingContext, tagAggregatorFactoryService, globalOptions, listenerProvider) + { + } + + protected override string FeatureAttributeName => FeatureAttribute.StringIndentation; + protected override string AdornmentLayerName => LayerName; + + protected override void CreateAdornmentManager(IWpfTextView textView) + { + // the manager keeps itself alive by listening to text view events. + _ = new StringIndentationAdornmentManager(ThreadingContext, textView, TagAggregatorFactoryService, AsyncListener, AdornmentLayerName); + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTag.cs b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTag.cs new file mode 100644 index 0000000000000..c3aa636a2ce4e --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTag.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Windows.Media; +using Microsoft.CodeAnalysis.Editor.Implementation.Adornments; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.StringIndentation +{ + /// + /// Tag that specifies how a string's content is indented. + /// + internal class StringIndentationTag : BrushTag + { + public readonly ImmutableArray OrderedHoleSpans; + + public StringIndentationTag( + IEditorFormatMap editorFormatMap, + ImmutableArray orderedHoleSpans) + : base(editorFormatMap) + { + OrderedHoleSpans = orderedHoleSpans; + } + + protected override Color? GetColor(IWpfTextView view, IEditorFormatMap editorFormatMap) + { + var brush = view.VisualElement.TryFindResource("outlining.verticalrule.foreground") as SolidColorBrush; + return brush?.Color; + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTaggerProvider.cs new file mode 100644 index 0000000000000..f955c10c1e74b --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTaggerProvider.cs @@ -0,0 +1,122 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.ComponentModel.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Implementation.Tagging; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Options; +using Microsoft.CodeAnalysis.Editor.Shared.Tagging; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Editor.Tagging; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.StringIndentation; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Tagging; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.StringIndentation +{ + /// + /// This factory is called to create taggers that provide information about how strings are indented. + /// + [Export(typeof(ITaggerProvider))] + [TagType(typeof(StringIndentationTag))] + [VisualStudio.Utilities.ContentType(ContentTypeNames.CSharpContentType)] + [VisualStudio.Utilities.ContentType(ContentTypeNames.VisualBasicContentType)] + internal partial class StringIndentationTaggerProvider : AsynchronousTaggerProvider + { + private readonly IEditorFormatMap _editorFormatMap; + + protected override IEnumerable> PerLanguageOptions => SpecializedCollections.SingletonEnumerable(FeatureOnOffOptions.StringIdentation); + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public StringIndentationTaggerProvider( + IThreadingContext threadingContext, + IEditorFormatMapService editorFormatMapService, + IGlobalOptionService globalOptions, + IAsynchronousOperationListenerProvider listenerProvider) + : base(threadingContext, globalOptions, listenerProvider.GetListener(FeatureAttribute.StringIndentation)) + { + _editorFormatMap = editorFormatMapService.GetEditorFormatMap("text"); + } + + protected override TaggerDelay EventChangeDelay => TaggerDelay.NearImmediate; + + /// + /// We want the span tracking mode to be inclusive here. That way if the user types space here: + /// + /// + /// var v = """ + /// goo + /// """ + /// ^ // here + /// + /// + /// then the span of the tag will grow to the right and the line will immediately redraw in the correct position + /// while we're in the process of recomputing the up to date tags. + /// + protected override SpanTrackingMode SpanTrackingMode => SpanTrackingMode.EdgeInclusive; + + protected override ITaggerEventSource CreateEventSource( + ITextView textView, ITextBuffer subjectBuffer) + { + return TaggerEventSources.Compose( + new EditorFormatMapChangedEventSource(_editorFormatMap), + TaggerEventSources.OnTextChanged(subjectBuffer)); + } + + protected override async Task ProduceTagsAsync( + TaggerContext context, DocumentSnapshotSpan documentSnapshotSpan, int? caretPosition, CancellationToken cancellationToken) + { + var document = documentSnapshotSpan.Document; + if (document == null) + return; + + if (!GlobalOptions.GetOption(FeatureOnOffOptions.StringIdentation, document.Project.Language)) + return; + + var service = document.GetLanguageService(); + if (service == null) + return; + + var snapshotSpan = documentSnapshotSpan.SnapshotSpan; + var regions = await service.GetStringIndentationRegionsAsync(document, snapshotSpan.Span.ToTextSpan(), cancellationToken).ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); + + if (regions.Length == 0) + return; + + var snapshot = snapshotSpan.Snapshot; + foreach (var region in regions) + { + var line = snapshot.GetLineFromPosition(region.IndentSpan.End); + + // If the indent is on the first column, then no need to actually show anything (plus we can't as we + // want to draw one column earlier, and that column doesn't exist). + if (line.Start == region.IndentSpan.End) + continue; + + context.AddTag(new TagSpan( + region.IndentSpan.ToSnapshotSpan(snapshot), + new StringIndentationTag( + _editorFormatMap, + region.OrderedHoleSpans.SelectAsArray(s => s.ToSnapshotSpan(snapshot))))); + } + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs index 2724752aec37f..ed537090ce98e 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs @@ -168,12 +168,14 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs var workspace = document.Project.Solution.Workspace; var supportsFeatureService = workspace.Services.GetRequiredService(); + var options = GlobalOptions.GetCodeActionOptions(document.Project.Language, isBlocking: false); + var fixesTask = GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, priority, isBlocking: false, cancellationToken); + addOperationScope, priority, options, cancellationToken); var refactoringsTask = GetRefactoringsAsync( state, supportsFeatureService, requestedActionCategories, GlobalOptions, workspace, document, selection, - addOperationScope, priority, isBlocking: false, cancellationToken); + addOperationScope, priority, options, cancellationToken); await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 65254beb59b73..0d2a67374b859 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -177,15 +177,18 @@ public bool TryGetTelemetryId(out Guid telemetryId) Func addOperationScope = description => operationContext?.AddScope(allowCancellation: true, string.Format(EditorFeaturesResources.Gathering_Suggestions_0, description)); + var options = GlobalOptions.GetCodeActionOptions(document.Project.Language, isBlocking: true); + // We convert the code fixes and refactorings to UnifiedSuggestedActionSets instead of // SuggestedActionSets so that we can share logic between local Roslyn and LSP. var fixesTask = GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, addOperationScope, CodeActionRequestPriority.None, - isBlocking: true, cancellationToken); + options, cancellationToken); + var refactoringsTask = GetRefactoringsAsync( state, supportsFeatureService, requestedActionCategories, GlobalOptions, workspace, document, selection, - addOperationScope, CodeActionRequestPriority.None, isBlocking: true, cancellationToken); + addOperationScope, CodeActionRequestPriority.None, options, cancellationToken); Task.WhenAll(fixesTask, refactoringsTask).WaitAndGetResult(cancellationToken); @@ -263,7 +266,7 @@ protected static Task> GetCodeFixesAsy SnapshotSpan range, Func addOperationScope, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, CancellationToken cancellationToken) { if (state.Target.Owner._codeFixService == null || @@ -275,7 +278,7 @@ protected static Task> GetCodeFixesAsy return UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( workspace, state.Target.Owner._codeFixService, document, range.Span.ToTextSpan(), - priority, isBlocking, addOperationScope, cancellationToken).AsTask(); + priority, options, addOperationScope, cancellationToken).AsTask(); } private static string GetFixCategory(DiagnosticSeverity severity) @@ -303,7 +306,7 @@ protected static Task> GetRefactorings TextSpan? selection, Func addOperationScope, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, CancellationToken cancellationToken) { if (!selection.HasValue) @@ -332,7 +335,7 @@ protected static Task> GetRefactorings var filterOutsideSelection = !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.Refactoring); return UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - workspace, state.Target.Owner._codeRefactoringService, document, selection.Value, priority, isBlocking, + workspace, state.Target.Owner._codeRefactoringService, document, selection.Value, priority, options, addOperationScope, filterOutsideSelection, cancellationToken); } @@ -439,6 +442,7 @@ await InvokeBelowInputPriorityAsync(() => private async Task TryGetRefactoringSuggestedActionCategoryAsync( Document document, TextSpan? selection, + CodeActionOptions options, CancellationToken cancellationToken) { using var state = _state.TryAddReference(); @@ -457,7 +461,7 @@ await InvokeBelowInputPriorityAsync(() => state.Target.SubjectBuffer.SupportsRefactorings()) { if (await state.Target.Owner._codeRefactoringService.HasRefactoringsAsync( - document, selection.Value, cancellationToken).ConfigureAwait(false)) + document, selection.Value, options, cancellationToken).ConfigureAwait(false)) { return PredefinedSuggestedActionCategoryNames.Refactoring; } @@ -610,6 +614,8 @@ private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId? c if (document == null) return null; + var options = GlobalOptions.GetCodeActionOptions(document.Project.Language, isBlocking: false); + using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); var linkedToken = linkedTokenSource.Token; @@ -621,7 +627,7 @@ private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId? c if (selection != null) { refactoringTask = Task.Run( - () => TryGetRefactoringSuggestedActionCategoryAsync(document, selection, linkedToken), linkedToken); + () => TryGetRefactoringSuggestedActionCategoryAsync(document, selection, options, linkedToken), linkedToken); } // If we happen to get the result of the error task before the refactoring task, diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs index b5d8b8a4d5b92..a99c015036d7e 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tags; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; diff --git a/src/EditorFeatures/Core.Wpf/LineSeparators/EditorFormatMapChangedEventSource.cs b/src/EditorFeatures/Core.Wpf/Tagging/EditorFormatMapChangedEventSource.cs similarity index 93% rename from src/EditorFeatures/Core.Wpf/LineSeparators/EditorFormatMapChangedEventSource.cs rename to src/EditorFeatures/Core.Wpf/Tagging/EditorFormatMapChangedEventSource.cs index 427fcf96cc48d..aa0e01715b7d7 100644 --- a/src/EditorFeatures/Core.Wpf/LineSeparators/EditorFormatMapChangedEventSource.cs +++ b/src/EditorFeatures/Core.Wpf/Tagging/EditorFormatMapChangedEventSource.cs @@ -5,7 +5,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.VisualStudio.Text.Classification; -namespace Microsoft.CodeAnalysis.Editor.Implementation.LineSeparators +namespace Microsoft.CodeAnalysis.Editor.Implementation.Tagging { internal sealed class EditorFormatMapChangedEventSource : AbstractTaggerEventSource { diff --git a/src/EditorFeatures/Core/CommandHandlers/AbstractGoToCommandHandler`2.cs b/src/EditorFeatures/Core/CommandHandlers/AbstractGoToCommandHandler`2.cs index e67a5e0bf9a74..87508b70e4ba4 100644 --- a/src/EditorFeatures/Core/CommandHandlers/AbstractGoToCommandHandler`2.cs +++ b/src/EditorFeatures/Core/CommandHandlers/AbstractGoToCommandHandler`2.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; @@ -33,6 +34,7 @@ internal abstract class AbstractGoToCommandHandler /// The current go-to command that is in progress. Tracked so that if we issue multiple find-impl commands that @@ -59,19 +61,21 @@ public AbstractGoToCommandHandler( IThreadingContext threadingContext, IStreamingFindUsagesPresenter streamingPresenter, IUIThreadOperationExecutor uiThreadOperationExecutor, - IAsynchronousOperationListener listener) + IAsynchronousOperationListener listener, + IGlobalOptionService globalOptions) { _threadingContext = threadingContext; _streamingPresenter = streamingPresenter; _uiThreadOperationExecutor = uiThreadOperationExecutor; _listener = listener; + _globalOptions = globalOptions; } public abstract string DisplayName { get; } protected abstract string ScopeDescription { get; } protected abstract FunctionId FunctionId { get; } - protected abstract Task FindActionAsync(Document document, int caretPosition, IFindUsagesContext context, CancellationToken cancellationToken); + protected abstract Task FindActionAsync(IFindUsagesContext context, Document document, int caretPosition, CancellationToken cancellationToken); public CommandState GetCommandState(TCommandArgs args) { @@ -161,11 +165,11 @@ private async Task ExecuteCommandWorkerAsync( // TLanguageService. Once we get the results back we'll then decide what to do with them. If we get only a // single result back, then we'll just go directly to it. Otherwise, we'll present the results in the // IStreamingFindUsagesPresenter. - var findContext = new BufferedFindUsagesContext(); + var findContext = new BufferedFindUsagesContext(_globalOptions); var cancellationToken = cancellationTokenSource.Token; var delayTask = Task.Delay(TaggerDelay.OnIdle.ComputeTimeDelay(), cancellationToken); - var findTask = Task.Run(() => FindResultsAsync(document, position, findContext, cancellationToken), cancellationToken); + var findTask = Task.Run(() => FindResultsAsync(findContext, document, position, cancellationToken), cancellationToken); var firstFinishedTask = await Task.WhenAny(delayTask, findTask).ConfigureAwait(false); if (cancellationToken.IsCancellationRequested) @@ -206,7 +210,7 @@ private async Task PresentResultsInStreamingPresenterAsync( { var cancellationToken = cancellationTokenSource.Token; await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var (presenterContext, presenterCancellationToken) = _streamingPresenter.StartSearch(this.DisplayName, supportsReferences: false); + var (presenterContext, presenterCancellationToken) = _streamingPresenter.StartSearch(DisplayName, supportsReferences: false); try { @@ -235,7 +239,7 @@ private async Task PresentResultsInStreamingPresenterAsync( } private async Task FindResultsAsync( - Document document, int position, IFindUsagesContext findContext, CancellationToken cancellationToken) + IFindUsagesContext findContext, Document document, int position, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken)) { @@ -253,7 +257,7 @@ await findContext.ReportInformationalMessageAsync( // We were able to find the doc prior to loading the workspace (or else we would not have the service). // So we better be able to find it afterwards. - await FindActionAsync(document, position, findContext, cancellationToken).ConfigureAwait(false); + await FindActionAsync(findContext, document, position, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/EditorFeatures/Core/CommandHandlers/BufferedFindUsagesContext.cs b/src/EditorFeatures/Core/CommandHandlers/BufferedFindUsagesContext.cs index bbb506ab873d4..a558da7b39434 100644 --- a/src/EditorFeatures/Core/CommandHandlers/BufferedFindUsagesContext.cs +++ b/src/EditorFeatures/Core/CommandHandlers/BufferedFindUsagesContext.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -29,6 +30,8 @@ private class State public ImmutableArray.Builder Definitions = ImmutableArray.CreateBuilder(); } + private readonly IGlobalOptionService _globalOptions; + /// /// Lock which controls access to all members below. /// @@ -46,8 +49,9 @@ private class State /// private State? _state = new(); - public BufferedFindUsagesContext() + public BufferedFindUsagesContext(IGlobalOptionService globalOptions) { + _globalOptions = globalOptions; } [MemberNotNullWhen(true, nameof(_streamingPresenterContext))] @@ -150,6 +154,9 @@ async ValueTask IStreamingProgressTracker.ItemsCompletedAsync(int count, Cancell #region IFindUsagesContext + ValueTask IFindUsagesContext.GetOptionsAsync(string language, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetFindUsagesOptions(language)); + async ValueTask IFindUsagesContext.ReportMessageAsync(string message, CancellationToken cancellationToken) { using var _ = await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs index 05e73e2a8bcdd..1f137a0d8c170 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs @@ -51,7 +51,7 @@ protected void Update() return; } - var configOptionsProvider = new WorkspaceAnalyzerConfigOptionsProvider(project.State); + var configOptionsProvider = new ProjectAnalyzerConfigOptionsProvider(project.State); var workspaceOptions = configOptionsProvider.GetOptionsForSourcePath(givenFolder.FullName); var result = project.GetAnalyzerConfigOptions(); var options = new CombinedAnalyzerConfigOptions(workspaceOptions, result); diff --git a/src/EditorFeatures/Core/EditorFeaturesResources.resx b/src/EditorFeatures/Core/EditorFeaturesResources.resx index ee32fef772903..0b786ff8a7041 100644 --- a/src/EditorFeatures/Core/EditorFeaturesResources.resx +++ b/src/EditorFeatures/Core/EditorFeaturesResources.resx @@ -724,9 +724,6 @@ Do you want to proceed? Go To Base - - The symbol has no implementations. - New name: {0} @@ -742,12 +739,6 @@ Do you want to proceed? Suggestion ellipses (…) - - '{0}' references - - - '{0}' implementations - '{0}' declarations @@ -886,12 +877,6 @@ Do you want to proceed? Waiting for background work to finish... - - The symbol has no base. - - - '{0}' bases - Rename symbol's _file Indicates that the file a symbol is defined in will also be renamed @@ -942,9 +927,6 @@ Do you want to proceed? Get help for '{0}' - - Get help for '{0}' from Bing - Gathering Suggestions - '{0}' @@ -1051,4 +1033,37 @@ Do you want to proceed? The results may be incomplete due to the solution still loading projects. + + JSON in string literal - Property Name + + + JSON in string literal - Array + + + JSON in string literal - Comment + + + JSON in string literal - Keyword + + + JSON in string literal - Number + + + JSON in string literal - Object + + + JSON in string literal - Operator + + + JSON in string literal - Punctuation + + + JSON in string literal - String + + + JSON in string literal - Text + + + JSON in string literal - Constructor Name + \ No newline at end of file diff --git a/src/EditorFeatures/Core/EmbeddedLanguages/AbstractEmbeddedLanguageEditorFeaturesProvider.cs b/src/EditorFeatures/Core/EmbeddedLanguages/AbstractEmbeddedLanguageEditorFeaturesProvider.cs index 8791704bd0b0f..ed609dcc8ab60 100644 --- a/src/EditorFeatures/Core/EmbeddedLanguages/AbstractEmbeddedLanguageEditorFeaturesProvider.cs +++ b/src/EditorFeatures/Core/EmbeddedLanguages/AbstractEmbeddedLanguageEditorFeaturesProvider.cs @@ -2,13 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Editor.EmbeddedLanguages.Json; +using Microsoft.CodeAnalysis.Editor.EmbeddedLanguages.RegularExpressions; using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; using Microsoft.CodeAnalysis.Features.EmbeddedLanguages; using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime; -using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions; namespace Microsoft.CodeAnalysis.Editor.EmbeddedLanguages { @@ -24,6 +23,7 @@ protected AbstractEmbeddedLanguageEditorFeaturesProvider(EmbeddedLanguageInfo in { Languages = ImmutableArray.Create( new DateAndTimeEmbeddedLanguageEditorFeatures(info), + new JsonEmbeddedLanguageEditorFeatures(info), new RegexEmbeddedLanguageEditorFeatures(this, info), new FallbackEmbeddedLanguage(info)); } diff --git a/src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonEmbeddedBraceMatcher.cs b/src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonEmbeddedBraceMatcher.cs new file mode 100644 index 0000000000000..f4f6a0dc6fcea --- /dev/null +++ b/src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonEmbeddedBraceMatcher.cs @@ -0,0 +1,109 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Editor.EmbeddedLanguages.Json +{ + using JsonToken = EmbeddedSyntaxToken; + + /// + /// Brace matching impl for embedded json strings. + /// + internal class JsonEmbeddedBraceMatcher : IBraceMatcher + { + private readonly EmbeddedLanguageInfo _info; + + public JsonEmbeddedBraceMatcher(EmbeddedLanguageInfo info) + { + _info = info; + } + + public async Task FindBracesAsync( + Document document, int position, BraceMatchingOptions options, CancellationToken cancellationToken) + { + if (!options.HighlightRelatedJsonComponentsUnderCursor) + return null; + + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var token = root.FindToken(position); + + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + var detector = JsonLanguageDetector.GetOrCreate(semanticModel.Compilation, _info); + + // We do support brace matching in strings that look very likely to be json, even if we aren't 100% certain + // if it truly is json. + var tree = detector.TryParseString(token, semanticModel, includeProbableStrings: true, cancellationToken); + if (tree == null) + return null; + + return GetMatchingBraces(tree, position); + } + + private static BraceMatchingResult? GetMatchingBraces(JsonTree tree, int position) + { + var virtualChar = tree.Text.Find(position); + if (virtualChar == null) + return null; + + var ch = virtualChar.Value; + return ch.Value is '{' or '[' or '(' or '}' or ']' or ')' + ? FindBraceHighlights(tree, ch) + : null; + } + + private static BraceMatchingResult? FindBraceHighlights(JsonTree tree, VirtualChar ch) + => FindBraceMatchingResult(tree.Root, ch); + + private static BraceMatchingResult? FindBraceMatchingResult(JsonNode node, VirtualChar ch) + { + var fullSpan = node.GetFullSpan(); + if (fullSpan == null) + return null; + + if (!fullSpan.Value.Contains(ch.Span.Start)) + return null; + + switch (node) + { + case JsonArrayNode array when Matches(array.OpenBracketToken, array.CloseBracketToken, ch): + return Create(array.OpenBracketToken, array.CloseBracketToken); + + case JsonObjectNode obj when Matches(obj.OpenBraceToken, obj.CloseBraceToken, ch): + return Create(obj.OpenBraceToken, obj.CloseBraceToken); + + case JsonConstructorNode cons when Matches(cons.OpenParenToken, cons.CloseParenToken, ch): + return Create(cons.OpenParenToken, cons.CloseParenToken); + } + + foreach (var child in node) + { + if (child.IsNode) + { + var result = FindBraceMatchingResult(child.Node, ch); + if (result != null) + return result; + } + } + + return null; + } + + private static BraceMatchingResult? Create(JsonToken open, JsonToken close) + => open.IsMissing || close.IsMissing + ? null + : new BraceMatchingResult(open.GetSpan(), close.GetSpan()); + + private static bool Matches(JsonToken openToken, JsonToken closeToken, VirtualChar ch) + => openToken.VirtualChars.Contains(ch) || closeToken.VirtualChars.Contains(ch); + } +} diff --git a/src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonEmbeddedLanguageEditorFeatures.cs b/src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonEmbeddedLanguageEditorFeatures.cs new file mode 100644 index 0000000000000..3bb439f6a5625 --- /dev/null +++ b/src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonEmbeddedLanguageEditorFeatures.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; + +namespace Microsoft.CodeAnalysis.Editor.EmbeddedLanguages.Json +{ + internal class JsonEmbeddedLanguageEditorFeatures : JsonEmbeddedLanguage, IEmbeddedLanguageEditorFeatures + { + public IBraceMatcher BraceMatcher { get; } + + public JsonEmbeddedLanguageEditorFeatures(EmbeddedLanguageInfo info) + : base(info) + { + BraceMatcher = new JsonEmbeddedBraceMatcher(info); + } + } +} diff --git a/src/EditorFeatures/Core/EmbeddedLanguages/RegularExpressions/RegexBraceMatcher.cs b/src/EditorFeatures/Core/EmbeddedLanguages/RegularExpressions/RegexBraceMatcher.cs index 3f562e8beec83..5eef26497de5a 100644 --- a/src/EditorFeatures/Core/EmbeddedLanguages/RegularExpressions/RegexBraceMatcher.cs +++ b/src/EditorFeatures/Core/EmbeddedLanguages/RegularExpressions/RegexBraceMatcher.cs @@ -8,12 +8,12 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; -namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions +namespace Microsoft.CodeAnalysis.Editor.EmbeddedLanguages.RegularExpressions { using RegexToken = EmbeddedSyntaxToken; using RegexTrivia = EmbeddedSyntaxTrivia; @@ -32,9 +32,7 @@ public RegexBraceMatcher(RegexEmbeddedLanguage language) Document document, int position, BraceMatchingOptions options, CancellationToken cancellationToken) { if (!options.HighlightRelatedRegexComponentsUnderCursor) - { return null; - } var tree = await _language.TryGetTreeAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false); return tree == null ? null : GetMatchingBraces(tree, position); @@ -42,24 +40,17 @@ public RegexBraceMatcher(RegexEmbeddedLanguage language) private static BraceMatchingResult? GetMatchingBraces(RegexTree tree, int position) { - var virtualChar = tree.Text.FirstOrNull(vc => vc.Span.Contains(position)); + var virtualChar = tree.Text.Find(position); if (virtualChar == null) - { return null; - } var ch = virtualChar.Value; - switch (ch.Value) + return ch.Value switch { - case '(': - case ')': - return FindGroupingBraces(tree, ch) ?? FindCommentBraces(tree, ch); - case '[': - case ']': - return FindCharacterClassBraces(tree, ch); - default: - return null; - } + '(' or ')' => FindGroupingBraces(tree, ch) ?? FindCommentBraces(tree, ch), + '[' or ']' => FindCharacterClassBraces(tree, ch), + _ => null, + }; } private static BraceMatchingResult? CreateResult(RegexToken open, RegexToken close) @@ -71,9 +62,7 @@ public RegexBraceMatcher(RegexEmbeddedLanguage language) { var trivia = FindTrivia(tree.Root, ch); if (trivia?.Kind != RegexKind.CommentTrivia) - { return null; - } var firstChar = trivia.Value.VirtualChars[0]; var lastChar = trivia.Value.VirtualChars[trivia.Value.VirtualChars.Length - 1]; @@ -106,9 +95,7 @@ private static TNode FindNode(RegexNode node, VirtualChar ch, Func(RegexNode node, VirtualChar ch, Func(RegexNode node, VirtualChar ch, Func(RegexNode node, VirtualChar ch, Func(RegexNode node, VirtualChar ch, Func From(project.Solution.Options, project.Language); public static BraceMatchingOptions From(OptionSet options, string language) => new( - HighlightRelatedRegexComponentsUnderCursor: options.GetOption(RegularExpressionsOptions.HighlightRelatedRegexComponentsUnderCursor, language)); + HighlightRelatedRegexComponentsUnderCursor: options.GetOption(RegularExpressionsOptions.HighlightRelatedRegexComponentsUnderCursor, language), + HighlightRelatedJsonComponentsUnderCursor: options.GetOption(JsonFeatureOptions.HighlightRelatedJsonComponentsUnderCursor, language)); } } diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs index fa7ba79bc627a..523837e1e7f4d 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs @@ -55,7 +55,7 @@ protected void NavigateToPosition(Workspace workspace, DocumentId documentId, in var navigationService = workspace.Services.GetRequiredService(); if (navigationService.CanNavigateToPosition(workspace, documentId, position, virtualSpace, cancellationToken)) { - navigationService.TryNavigateToPosition(workspace, documentId, position, virtualSpace, options: null, cancellationToken); + navigationService.TryNavigateToPosition(workspace, documentId, position, virtualSpace, NavigationOptions.Default, cancellationToken); } else { diff --git a/src/EditorFeatures/Core/ExternalAccess/UnitTesting/Api/UnitTestingGlobalOptions.cs b/src/EditorFeatures/Core/ExternalAccess/UnitTesting/Api/UnitTestingGlobalOptions.cs new file mode 100644 index 0000000000000..b5efe513b4830 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/UnitTesting/Api/UnitTestingGlobalOptions.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Remote; + +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api +{ + [Export(typeof(UnitTestingGlobalOptions)), Shared] + internal sealed class UnitTestingGlobalOptions + { + private readonly IGlobalOptionService _globalOptions; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public UnitTestingGlobalOptions(IGlobalOptionService globalOptions) + { + _globalOptions = globalOptions; + } + + public bool IsServiceHubProcessCoreClr + => _globalOptions.GetOption(RemoteHostOptions.OOPCoreClrFeatureFlag); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/ITypeScriptGoToDefinitionServiceFactoryImplementation.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/ITypeScriptGoToDefinitionServiceFactoryImplementation.cs new file mode 100644 index 0000000000000..03d7813de6eb7 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/ITypeScriptGoToDefinitionServiceFactoryImplementation.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal interface ITypeScriptGoToDefinitionServiceFactoryImplementation + { + ILanguageService CreateLanguageService(HostLanguageServices languageServices); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs index 9777e2e4aeab3..1c3e311b1dfb5 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs @@ -4,6 +4,7 @@ #nullable disable +using System; using System.Threading; using System.Threading.Tasks; @@ -12,8 +13,8 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api /// /// Language service that allows a language to participate in the editor's inline rename feature. /// - internal interface IVSTypeScriptEditorInlineRenameService + internal abstract class VSTypeScriptEditorInlineRenameServiceImplementation { - Task GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken); + public abstract Task GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken); } } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs index cee552048774a..5c7d88c74ec8c 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs @@ -2,9 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.Navigation; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api { @@ -28,6 +31,8 @@ internal interface IVSTypeScriptFindUsagesContext ValueTask OnDefinitionFoundAsync(VSTypeScriptDefinitionItem definition, CancellationToken cancellationToken); ValueTask OnReferenceFoundAsync(VSTypeScriptSourceReferenceItem reference, CancellationToken cancellationToken); + + ValueTask OnCompletedAsync(CancellationToken cancellationToken); } internal interface IVSTypeScriptStreamingProgressTracker @@ -36,49 +41,117 @@ internal interface IVSTypeScriptStreamingProgressTracker ValueTask ItemCompletedAsync(CancellationToken cancellationToken); } - internal class VSTypeScriptDefinitionItem + internal abstract class VSTypeScriptDefinitionItemNavigator + { + public abstract Task CanNavigateToAsync(Workspace workspace, CancellationToken cancellationToken); + public abstract Task TryNavigateToAsync(Workspace workspace, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken); + } + + internal sealed class VSTypeScriptDefinitionItem { - public VSTypeScriptDefinitionItem( + private sealed class ExternalDefinitionItem : DefinitionItem + { + private readonly VSTypeScriptDefinitionItemNavigator _navigator; + + internal override bool IsExternal => true; + + public ExternalDefinitionItem(VSTypeScriptDefinitionItemNavigator navigator, ImmutableArray tags, ImmutableArray displayParts) + : base(tags, + displayParts, + ImmutableArray.Empty, + originationParts: default, + sourceSpans: default, + properties: null, + displayIfNoReferences: true) + { + _navigator = navigator; + } + + public override Task CanNavigateToAsync(Workspace workspace, CancellationToken cancellationToken) + => _navigator.CanNavigateToAsync(workspace, cancellationToken); + + public override Task TryNavigateToAsync(Workspace workspace, NavigationOptions options, CancellationToken cancellationToken) + => _navigator.TryNavigateToAsync(workspace, options.PreferProvisionalTab, options.ActivateTab, cancellationToken); + } + + internal readonly DefinitionItem UnderlyingObject; + + internal VSTypeScriptDefinitionItem(DefinitionItem underlyingObject) + => UnderlyingObject = underlyingObject; + + public static VSTypeScriptDefinitionItem Create( ImmutableArray tags, ImmutableArray displayParts, - ImmutableArray sourceSpans, + ImmutableArray sourceSpans, ImmutableArray nameDisplayParts = default, - ImmutableDictionary? properties = null, - ImmutableDictionary? displayableProperties = null, bool displayIfNoReferences = true) { - Tags = tags; - DisplayParts = displayParts; - SourceSpans = sourceSpans; - NameDisplayParts = nameDisplayParts; - Properties = properties; - DisplayableProperties = displayableProperties; - DisplayIfNoReferences = displayIfNoReferences; + return new(DefinitionItem.Create( + tags, displayParts, sourceSpans.SelectAsArray(span => span.ToDocumentSpan()), nameDisplayParts, + properties: null, displayableProperties: ImmutableDictionary.Empty, displayIfNoReferences: displayIfNoReferences)); } - public ImmutableArray Tags { get; } - public ImmutableArray DisplayParts { get; } - public ImmutableArray SourceSpans { get; } - public ImmutableArray NameDisplayParts { get; } - public ImmutableDictionary? Properties { get; } - public ImmutableDictionary? DisplayableProperties { get; } - public bool DisplayIfNoReferences { get; } + public static VSTypeScriptDefinitionItem CreateExternal( + VSTypeScriptDefinitionItemNavigator navigator, + ImmutableArray tags, + ImmutableArray displayParts) + => new(new ExternalDefinitionItem(navigator, tags, displayParts)); + + [Obsolete] + public static VSTypeScriptDefinitionItem Create(VSTypeScriptDefinitionItemBase item) + => new(item); + + public ImmutableArray Tags => UnderlyingObject.Tags; + public ImmutableArray DisplayParts => UnderlyingObject.DisplayParts; + + public ImmutableArray GetSourceSpans() + => UnderlyingObject.SourceSpans.SelectAsArray(span => new VSTypeScriptDocumentSpan(span)); + + public Task CanNavigateToAsync(Workspace workspace, CancellationToken cancellationToken) + => UnderlyingObject.CanNavigateToAsync(workspace, cancellationToken); + + public Task TryNavigateToAsync(Workspace workspace, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) + => UnderlyingObject.TryNavigateToAsync(workspace, new NavigationOptions(showInPreviewTab, activateTab), cancellationToken); } - internal class VSTypeScriptSourceReferenceItem + internal sealed class VSTypeScriptSourceReferenceItem { + internal readonly SourceReferenceItem UnderlyingObject; + public VSTypeScriptSourceReferenceItem( VSTypeScriptDefinitionItem definition, - DocumentSpan sourceSpan, - SymbolUsageInfo symbolUsageInfo) + VSTypeScriptDocumentSpan sourceSpan, + VSTypeScriptSymbolUsageInfo symbolUsageInfo) { - Definition = definition; - SourceSpan = sourceSpan; - SymbolUsageInfo = symbolUsageInfo; + UnderlyingObject = new SourceReferenceItem(definition.UnderlyingObject, sourceSpan.ToDocumentSpan(), symbolUsageInfo.UnderlyingObject); } - public VSTypeScriptDefinitionItem Definition { get; } - public DocumentSpan SourceSpan { get; } - public SymbolUsageInfo SymbolUsageInfo { get; } + public VSTypeScriptDocumentSpan GetSourceSpan() + => new(UnderlyingObject.SourceSpan); + } + + internal readonly struct VSTypeScriptSymbolUsageInfo + { + internal readonly SymbolUsageInfo UnderlyingObject; + + private VSTypeScriptSymbolUsageInfo(SymbolUsageInfo underlyingObject) + => UnderlyingObject = underlyingObject; + + public static VSTypeScriptSymbolUsageInfo Create(VSTypeScriptValueUsageInfo valueUsageInfo) + => new(SymbolUsageInfo.Create((ValueUsageInfo)valueUsageInfo)); + } + + [Flags] + internal enum VSTypeScriptValueUsageInfo + { + None = ValueUsageInfo.None, + Read = ValueUsageInfo.Read, + Write = ValueUsageInfo.Write, + Reference = ValueUsageInfo.Reference, + Name = ValueUsageInfo.Name, + ReadWrite = ValueUsageInfo.ReadWrite, + ReadableReference = ValueUsageInfo.ReadableReference, + WritableReference = ValueUsageInfo.WritableReference, + ReadableWritableReference = ValueUsageInfo.ReadableWritableReference } } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptGoToDefinitionService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptGoToDefinitionService.cs new file mode 100644 index 0000000000000..cb8785f71d675 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptGoToDefinitionService.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal interface IVSTypeScriptGoToDefinitionService + { + Task?> FindDefinitionsAsync(Document document, int position, CancellationToken cancellationToken); + bool TryGoToDefinition(Document document, int position, CancellationToken cancellationToken); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptGoToDefinitionServiceFactoryImplementation.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptGoToDefinitionServiceFactoryImplementation.cs new file mode 100644 index 0000000000000..f9c7e5777716a --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptGoToDefinitionServiceFactoryImplementation.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal interface IVSTypeScriptGoToDefinitionServiceFactoryImplementation + { + IVSTypeScriptGoToDefinitionService CreateLanguageService(HostLanguageServices languageServices); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptGoToSymbolServiceImplementation.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptGoToSymbolServiceImplementation.cs new file mode 100644 index 0000000000000..3849cd9367bf4 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptGoToSymbolServiceImplementation.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal interface IVSTypeScriptGoToSymbolServiceImplementation + { + Task GetSymbolsAsync(VSTypeScriptGoToSymbolContext context); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameInfo.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameInfo.cs deleted file mode 100644 index fc7b0ec2d5ce5..0000000000000 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameInfo.cs +++ /dev/null @@ -1,103 +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.Generic; -using System.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api -{ - internal interface IVSTypeScriptInlineRenameInfo - { - /// - /// Whether or not the entity at the selected location can be renamed. - /// - bool CanRename { get; } - - /// - /// Provides the reason that can be displayed to the user if the entity at the selected - /// location cannot be renamed. - /// - string LocalizedErrorMessage { get; } - - /// - /// The span of the entity that is being renamed. - /// - TextSpan TriggerSpan { get; } - - /// - /// Whether or not this entity has overloads that can also be renamed if the user wants. - /// - bool HasOverloads { get; } - - /// - /// Whether the Rename Overloads option should be forced to true. Used if rename is invoked from within a nameof expression. - /// - bool ForceRenameOverloads { get; } - - /// - /// The short name of the symbol being renamed, for use in displaying information to the user. - /// - string DisplayName { get; } - - /// - /// The full name of the symbol being renamed, for use in displaying information to the user. - /// - string FullDisplayName { get; } - - /// - /// The glyph for the symbol being renamed, for use in displaying information to the user. - /// - VSTypeScriptGlyph Glyph { get; } - - /// - /// The locations of the symbol being renamed. - /// - ImmutableArray DefinitionLocations { get; } - - /// - /// Gets the final name of the symbol if the user has typed the provided replacement text - /// in the editor. Normally, the final name will be same as the replacement text. However, - /// that may not always be the same. For example, when renaming an attribute the replacement - /// text may be "NewName" while the final symbol name might be "NewNameAttribute". - /// - string GetFinalSymbolName(string replacementText); - - /// - /// Returns the actual span that should be edited in the buffer for a given rename reference - /// location. - /// - TextSpan GetReferenceEditSpan(VSTypeScriptInlineRenameLocationWrapper location, CancellationToken cancellationToken); - - /// - /// Returns the actual span that should be edited in the buffer for a given rename conflict - /// location. - /// - TextSpan? GetConflictEditSpan(VSTypeScriptInlineRenameLocationWrapper location, string replacementText, CancellationToken cancellationToken); - - /// - /// Determine the set of locations to rename given the provided options. May be called - /// multiple times. For example, this can be called one time for the initial set of - /// locations to rename, as well as any time the rename options are changed by the user. - /// - Task FindRenameLocationsAsync(OptionSet optionSet, CancellationToken cancellationToken); - - /// - /// Called before the rename is applied to the specified documents in the workspace. Return - /// if rename should proceed, or if it should be canceled. - /// - bool TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText); - - /// - /// Called after the rename is applied to the specified documents in the workspace. Return - /// if this operation succeeded, or if it failed. - /// - bool TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText); - } -} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameLocationSet.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameLocationSet.cs index dc77279d9d754..864646d3598c8 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameLocationSet.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameLocationSet.cs @@ -4,21 +4,28 @@ #nullable disable +using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api { - internal interface IVSTypeScriptInlineRenameLocationSet + internal abstract class VSTypeScriptInlineRenameLocationSet : IInlineRenameLocationSet { /// /// The set of locations that need to be updated with the replacement text that the user /// has entered in the inline rename session. These are the locations are all relative /// to the solution when the inline rename session began. /// - IList Locations { get; } + public abstract IList Locations { get; } + + IList IInlineRenameLocationSet.Locations + => Locations?.Select(x => new InlineRenameLocation(x.Document, x.TextSpan)).ToList(); /// /// Returns the set of replacements and their possible resolutions if the user enters the @@ -26,6 +33,9 @@ internal interface IVSTypeScriptInlineRenameLocationSet /// and TextSpan in the original solution, and specify their new span and possible conflict /// resolution. /// - Task GetReplacementsAsync(string replacementText, OptionSet optionSet, CancellationToken cancellationToken); + public abstract Task GetReplacementsAsync(string replacementText, CancellationToken cancellationToken); + + async Task IInlineRenameLocationSet.GetReplacementsAsync(string replacementText, SymbolRenameOptions options, CancellationToken cancellationToken) + => await GetReplacementsAsync(replacementText, cancellationToken).ConfigureAwait(false); } } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameReplacementInfo.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameReplacementInfo.cs index e312773631a5a..28b3367c75a73 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameReplacementInfo.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptInlineRenameReplacementInfo.cs @@ -4,31 +4,36 @@ #nullable disable +using System; using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.Editor; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api - { - internal interface IVSTypeScriptInlineRenameReplacementInfo + internal abstract class VSTypeScriptInlineRenameReplacementInfo : IInlineRenameReplacementInfo { /// /// The solution obtained after resolving all conflicts. /// - Solution NewSolution { get; } + public abstract Solution NewSolution { get; } /// /// Whether or not the replacement text entered by the user is valid. /// - bool ReplacementTextValid { get; } + public abstract bool ReplacementTextValid { get; } /// /// The documents that need to be updated. /// - IEnumerable DocumentIds { get; } + public abstract IEnumerable DocumentIds { get; } /// /// Returns all the replacements that need to be performed for the specified document. /// - IEnumerable GetReplacements(DocumentId documentId); + public abstract IEnumerable GetReplacements(DocumentId documentId); + + IEnumerable IInlineRenameReplacementInfo.GetReplacements(DocumentId documentId) + => GetReplacements(documentId).Select(r => r.UnderlyingObject); } } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptStreamingFindUsagesPresenterAccessor.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptStreamingFindUsagesPresenterAccessor.cs new file mode 100644 index 0000000000000..ab3b09da58289 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptStreamingFindUsagesPresenterAccessor.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal interface IVSTypeScriptStreamingFindUsagesPresenterAccessor + { + (IVSTypeScriptFindUsagesContext context, CancellationToken cancellationToken) StartSearch( + string title, bool supportsReferences); + + void ClearAll(); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptBraceMatcher.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptBraceMatcher.cs deleted file mode 100644 index 0474c8068a5ea..0000000000000 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptBraceMatcher.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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor; - -namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api -{ - [Obsolete] - internal abstract class VSTypeScriptBraceMatcher : IBraceMatcher - { - Task IBraceMatcher.FindBracesAsync(Document document, int position, BraceMatchingOptions options, CancellationToken cancellationToken) - => FindBracesAsync(document, position, cancellationToken); - - protected abstract Task FindBracesAsync(Document document, int position, CancellationToken cancellationToken); - } -} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.cs new file mode 100644 index 0000000000000..9aa9cc2e5a526 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.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. + +#nullable disable + +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal readonly struct VSTypeScriptDocumentSpan + { + public Document Document { get; } + public TextSpan SourceSpan { get; } + + public VSTypeScriptDocumentSpan(Document document, TextSpan sourceSpan) + { + Document = document; + SourceSpan = sourceSpan; + } + + internal VSTypeScriptDocumentSpan(DocumentSpan span) + : this(span.Document, span.SourceSpan) + { + } + + internal DocumentSpan ToDocumentSpan() + => new(Document, SourceSpan); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGoToSymbolContext.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGoToSymbolContext.cs new file mode 100644 index 0000000000000..ddde670b0cb32 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGoToSymbolContext.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Editor.GoToDefinition; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal sealed class VSTypeScriptGoToSymbolContext + { + internal readonly GoToSymbolContext UnderlyingObject; + + internal VSTypeScriptGoToSymbolContext(GoToSymbolContext underlyingObject) + => UnderlyingObject = underlyingObject; + + public Document Document => UnderlyingObject.Document; + public int Position => UnderlyingObject.Position; + public CancellationToken CancellationToken => UnderlyingObject.CancellationToken; + + public TextSpan Span + { + get => UnderlyingObject.Span; + set => UnderlyingObject.Span = value; + } + + public void AddItem(string key, VSTypeScriptDefinitionItem item) + => UnderlyingObject.AddItem(key, item.UnderlyingObject); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs index 91ed9fe7fe016..1e6ca0a8e1a4f 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameInfo.cs @@ -4,77 +4,58 @@ #nullable disable +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api { - internal sealed class VSTypeScriptInlineRenameInfo : IInlineRenameInfo + internal abstract class VSTypeScriptInlineRenameInfo : IInlineRenameInfo { - private readonly IVSTypeScriptInlineRenameInfo _info; - - public VSTypeScriptInlineRenameInfo(IVSTypeScriptInlineRenameInfo info) - { - Contract.ThrowIfNull(info); - _info = info; - } - - public bool CanRename => _info.CanRename; - - public string LocalizedErrorMessage => _info.LocalizedErrorMessage; - - public TextSpan TriggerSpan => _info.TriggerSpan; - - public bool HasOverloads => _info.HasOverloads; - - public bool ForceRenameOverloads => _info.ForceRenameOverloads; - - public string DisplayName => _info.DisplayName; - - public string FullDisplayName => _info.FullDisplayName; - - public Glyph Glyph => VSTypeScriptGlyphHelpers.ConvertTo(_info.Glyph); - - public ImmutableArray DefinitionLocations => _info.DefinitionLocations; - - public async Task FindRenameLocationsAsync(OptionSet optionSet, CancellationToken cancellationToken) - { - var set = await _info.FindRenameLocationsAsync(optionSet, cancellationToken).ConfigureAwait(false); - if (set != null) - { - return new VSTypeScriptInlineRenameLocationSet(set); - } - else - { - return null; - } - } - - public TextSpan? GetConflictEditSpan(InlineRenameLocation location, string triggerText, string replacementText, CancellationToken cancellationToken) - { - return _info.GetConflictEditSpan(new VSTypeScriptInlineRenameLocationWrapper( + public abstract bool CanRename { get; } + public abstract string DisplayName { get; } + public abstract string FullDisplayName { get; } + public abstract VSTypeScriptGlyph Glyph { get; } + public abstract bool HasOverloads { get; } + public abstract bool ForceRenameOverloads { get; } + public abstract string LocalizedErrorMessage { get; } + public abstract TextSpan TriggerSpan { get; } + public abstract ImmutableArray DefinitionLocations { get; } + public abstract Task FindRenameLocationsAsync(bool renameInStrings, bool renameInComments, CancellationToken cancellationToken); + public abstract TextSpan? GetConflictEditSpan(VSTypeScriptInlineRenameLocationWrapper location, string replacementText, CancellationToken cancellationToken); + public abstract string GetFinalSymbolName(string replacementText); + public abstract TextSpan GetReferenceEditSpan(VSTypeScriptInlineRenameLocationWrapper location, CancellationToken cancellationToken); + + bool IInlineRenameInfo.MustRenameOverloads + => ForceRenameOverloads; + + Glyph IInlineRenameInfo.Glyph + => VSTypeScriptGlyphHelpers.ConvertTo(Glyph); + + ImmutableArray IInlineRenameInfo.DefinitionLocations + => DefinitionLocations.SelectAsArray(l => new DocumentSpan(l.Document, l.SourceSpan)); + + async Task IInlineRenameInfo.FindRenameLocationsAsync(SymbolRenameOptions options, CancellationToken cancellationToken) + => await FindRenameLocationsAsync(options.RenameInStrings, options.RenameInComments, cancellationToken).ConfigureAwait(false); + + TextSpan? IInlineRenameInfo.GetConflictEditSpan(InlineRenameLocation location, string triggerText, string replacementText, CancellationToken cancellationToken) + => GetConflictEditSpan(new VSTypeScriptInlineRenameLocationWrapper( new InlineRenameLocation(location.Document, location.TextSpan)), replacementText, cancellationToken); - } - - public string GetFinalSymbolName(string replacementText) - => _info.GetFinalSymbolName(replacementText); - public TextSpan GetReferenceEditSpan(InlineRenameLocation location, string triggerText, CancellationToken cancellationToken) - { - return _info.GetReferenceEditSpan(new VSTypeScriptInlineRenameLocationWrapper( + TextSpan IInlineRenameInfo.GetReferenceEditSpan(InlineRenameLocation location, string triggerText, CancellationToken cancellationToken) + => GetReferenceEditSpan(new VSTypeScriptInlineRenameLocationWrapper( new InlineRenameLocation(location.Document, location.TextSpan)), cancellationToken); - } - public bool TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) - => _info.TryOnAfterGlobalSymbolRenamed(workspace, changedDocumentIDs, replacementText); + bool IInlineRenameInfo.TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) + => true; - public bool TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) - => _info.TryOnBeforeGlobalSymbolRenamed(workspace, changedDocumentIDs, replacementText); + bool IInlineRenameInfo.TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) + => true; } } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameLocationSet.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameLocationSet.cs deleted file mode 100644 index 37f453668dce1..0000000000000 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameLocationSet.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. - -#nullable disable - -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor; -using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api -{ - internal sealed class VSTypeScriptInlineRenameLocationSet : IInlineRenameLocationSet - { - private readonly IVSTypeScriptInlineRenameLocationSet _set; - - public VSTypeScriptInlineRenameLocationSet(IVSTypeScriptInlineRenameLocationSet set) - { - Contract.ThrowIfNull(set); - _set = set; - Locations = set.Locations?.Select(x => new InlineRenameLocation(x.Document, x.TextSpan)).ToList(); - } - - public IList Locations { get; } - - public async Task GetReplacementsAsync(string replacementText, OptionSet optionSet, CancellationToken cancellationToken) - { - var info = await _set.GetReplacementsAsync(replacementText, optionSet, cancellationToken).ConfigureAwait(false); - if (info != null) - { - return new VSTypeScriptInlineRenameReplacementInfo(info); - } - else - { - return null; - } - } - } -} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementInfo.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementInfo.cs deleted file mode 100644 index 60fb037582482..0000000000000 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis.Editor; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api -{ - internal sealed class VSTypeScriptInlineRenameReplacementInfo : IInlineRenameReplacementInfo - { - private readonly IVSTypeScriptInlineRenameReplacementInfo _info; - - public VSTypeScriptInlineRenameReplacementInfo(IVSTypeScriptInlineRenameReplacementInfo info) - { - Contract.ThrowIfNull(info); - _info = info; - } - - public Solution NewSolution => _info.NewSolution; - - public bool ReplacementTextValid => _info.ReplacementTextValid; - - public IEnumerable DocumentIds => _info.DocumentIds; - - public IEnumerable GetReplacements(DocumentId documentId) - { - return _info.GetReplacements(documentId)?.Select(x => - new InlineRenameReplacement(VSTypeScriptInlineRenameReplacementKindHelpers.ConvertTo(x.Kind), x.OriginalSpan, x.NewSpan)); - } - } -} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementWrapper.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementWrapper.cs index f71c0a6f60455..f0c9c3fa5cb4e 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementWrapper.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptInlineRenameReplacementWrapper.cs @@ -11,13 +11,13 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api { internal readonly struct VSTypeScriptInlineRenameReplacementWrapper { - private readonly InlineRenameReplacement _underlyingObject; + internal readonly InlineRenameReplacement UnderlyingObject; public VSTypeScriptInlineRenameReplacementWrapper(InlineRenameReplacement underlyingObject) - => _underlyingObject = underlyingObject; + => UnderlyingObject = underlyingObject; - public VSTypeScriptInlineRenameReplacementKind Kind => VSTypeScriptInlineRenameReplacementKindHelpers.ConvertFrom(_underlyingObject.Kind); - public TextSpan OriginalSpan => _underlyingObject.OriginalSpan; - public TextSpan NewSpan => _underlyingObject.NewSpan; + public VSTypeScriptInlineRenameReplacementKind Kind => VSTypeScriptInlineRenameReplacementKindHelpers.ConvertFrom(UnderlyingObject.Kind); + public TextSpan OriginalSpan => UnderlyingObject.OriginalSpan; + public TextSpan NewSpan => UnderlyingObject.NewSpan; } } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptWellKnownSymbolTypes.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptWellKnownSymbolTypes.cs new file mode 100644 index 0000000000000..aa9e05e30ec6f --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptWellKnownSymbolTypes.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Editor.GoToDefinition; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api +{ + internal static class VSTypeScriptWellKnownSymbolTypes + { + public const string Definition = WellKnownSymbolTypes.Definition; + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs index cf14751ed5a01..e33c03b20ee05 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs @@ -2,16 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - +using System; +using System.Composition; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; -using Roslyn.Utilities; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using System; +using Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; +using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript { @@ -19,27 +17,24 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript [ExportLanguageService(typeof(IEditorInlineRenameService), InternalLanguageNames.TypeScript)] internal sealed class VSTypeScriptEditorInlineRenameService : IEditorInlineRenameService { - private readonly Lazy _service; + private readonly Lazy? _service; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VSTypeScriptEditorInlineRenameService(Lazy service) + public VSTypeScriptEditorInlineRenameService( + [Import(AllowDefault = true)] Lazy? service) { - Contract.ThrowIfNull(service); _service = service; } public async Task GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken) { - var info = await _service.Value.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false); - if (info != null) + if (_service != null) { - return new VSTypeScriptInlineRenameInfo(info); - } - else - { - return null; + return await _service.Value.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false); } + + return AbstractEditorInlineRenameService.DefaultFailureInfo; } } } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFindUsagesContext.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFindUsagesContext.cs new file mode 100644 index 0000000000000..1da49573dac3c --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFindUsagesContext.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript +{ + internal sealed class VSTypeScriptFindUsagesContext : IVSTypeScriptFindUsagesContext + { + internal readonly FindUsagesContext UnderlyingObject; + + public VSTypeScriptFindUsagesContext(FindUsagesContext underlyingObject) + => UnderlyingObject = underlyingObject; + + public IVSTypeScriptStreamingProgressTracker ProgressTracker + => new VSTypeScriptStreamingProgressTracker(UnderlyingObject.ProgressTracker); + + public ValueTask ReportMessageAsync(string message, CancellationToken cancellationToken) + => UnderlyingObject.ReportMessageAsync(message, cancellationToken); + + public ValueTask SetSearchTitleAsync(string title, CancellationToken cancellationToken) + => UnderlyingObject.SetSearchTitleAsync(title, cancellationToken); + + public ValueTask OnDefinitionFoundAsync(VSTypeScriptDefinitionItem definition, CancellationToken cancellationToken) + => UnderlyingObject.OnDefinitionFoundAsync(definition.UnderlyingObject, cancellationToken); + + public ValueTask OnReferenceFoundAsync(VSTypeScriptSourceReferenceItem reference, CancellationToken cancellationToken) + => UnderlyingObject.OnReferenceFoundAsync(reference.UnderlyingObject, cancellationToken); + + public ValueTask OnCompletedAsync(CancellationToken cancellationToken) + => UnderlyingObject.OnCompletedAsync(cancellationToken); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFindUsagesService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFindUsagesService.cs index caa32af454098..c20f19f925add 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFindUsagesService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFindUsagesService.cs @@ -3,20 +3,20 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Composition; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Utilities; +using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.ExternalAccess.VSTypeScript +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript { [ExportLanguageService(typeof(IFindUsagesService), InternalLanguageNames.TypeScript), Shared] - internal class VSTypeScriptFindUsagesService : IFindUsagesService + internal sealed class VSTypeScriptFindUsagesService : IFindUsagesService { private readonly IVSTypeScriptFindUsagesService _underlyingService; @@ -27,23 +27,23 @@ public VSTypeScriptFindUsagesService(IVSTypeScriptFindUsagesService underlyingSe _underlyingService = underlyingService; } - public Task FindReferencesAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) - => _underlyingService.FindReferencesAsync(document, position, new VSTypeScriptFindUsagesContext(context), cancellationToken); + public Task FindReferencesAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) + => _underlyingService.FindReferencesAsync(document, position, new Context(context), cancellationToken); - public Task FindImplementationsAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) - => _underlyingService.FindImplementationsAsync(document, position, new VSTypeScriptFindUsagesContext(context), cancellationToken); + public Task FindImplementationsAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) + => _underlyingService.FindImplementationsAsync(document, position, new Context(context), cancellationToken); - private class VSTypeScriptFindUsagesContext : IVSTypeScriptFindUsagesContext + private sealed class Context : IVSTypeScriptFindUsagesContext { private readonly IFindUsagesContext _context; - private readonly Dictionary _definitionItemMap = new(); - public VSTypeScriptFindUsagesContext(IFindUsagesContext context) + public Context(IFindUsagesContext context) { _context = context; } - public IVSTypeScriptStreamingProgressTracker ProgressTracker => new VSTypeScriptStreamingProgressTracker(_context.ProgressTracker); + public IVSTypeScriptStreamingProgressTracker ProgressTracker + => new ProgressTracker(_context.ProgressTracker); public ValueTask ReportMessageAsync(string message, CancellationToken cancellationToken) => _context.ReportMessageAsync(message, cancellationToken); @@ -51,45 +51,21 @@ public ValueTask ReportMessageAsync(string message, CancellationToken cancellati public ValueTask SetSearchTitleAsync(string title, CancellationToken cancellationToken) => _context.SetSearchTitleAsync(title, cancellationToken); - private DefinitionItem GetOrCreateDefinitionItem(VSTypeScriptDefinitionItem item) - { - lock (_definitionItemMap) - { - if (!_definitionItemMap.TryGetValue(item, out var result)) - { - result = DefinitionItem.Create( - item.Tags, - item.DisplayParts, - item.SourceSpans, - item.NameDisplayParts, - item.Properties, - item.DisplayableProperties, - item.DisplayIfNoReferences); - _definitionItemMap.Add(item, result); - } - - return result; - } - } - public ValueTask OnDefinitionFoundAsync(VSTypeScriptDefinitionItem definition, CancellationToken cancellationToken) - { - var item = GetOrCreateDefinitionItem(definition); - return _context.OnDefinitionFoundAsync(item, cancellationToken); - } + => _context.OnDefinitionFoundAsync(definition.UnderlyingObject, cancellationToken); public ValueTask OnReferenceFoundAsync(VSTypeScriptSourceReferenceItem reference, CancellationToken cancellationToken) - { - var item = GetOrCreateDefinitionItem(reference.Definition); - return _context.OnReferenceFoundAsync(new SourceReferenceItem(item, reference.SourceSpan, reference.SymbolUsageInfo), cancellationToken); - } + => _context.OnReferenceFoundAsync(reference.UnderlyingObject, cancellationToken); + + public ValueTask OnCompletedAsync(CancellationToken cancellationToken) + => ValueTaskFactory.CompletedTask; } - private class VSTypeScriptStreamingProgressTracker : IVSTypeScriptStreamingProgressTracker + private sealed class ProgressTracker : IVSTypeScriptStreamingProgressTracker { private readonly IStreamingProgressTracker _progressTracker; - public VSTypeScriptStreamingProgressTracker(IStreamingProgressTracker progressTracker) + public ProgressTracker(IStreamingProgressTracker progressTracker) { _progressTracker = progressTracker; } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFormattingInteractionService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFormattingInteractionService.cs index 6a6bb7990ca23..6326622d89390 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFormattingInteractionService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFormattingInteractionService.cs @@ -31,7 +31,7 @@ public VSTypeScriptFormattingInteractionService(IVSTypeScriptFormattingInteracti public bool SupportsFormatOnPaste => _implementation.SupportsFormatOnPaste; public bool SupportsFormatOnReturn => _implementation.SupportsFormatOnReturn; - public bool SupportsFormattingOnTypedCharacter(Document document, char ch) + public bool SupportsFormattingOnTypedCharacter(Document document, AutoFormattingOptions options, char ch) => _implementation.SupportsFormattingOnTypedCharacter(document, ch); public Task> GetFormattingChangesAsync(Document document, TextSpan? textSpan, DocumentOptionSet? documentOptions, CancellationToken cancellationToken) diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptGoToDefinitionServiceFactory.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptGoToDefinitionServiceFactory.cs new file mode 100644 index 0000000000000..4f9904cac0182 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptGoToDefinitionServiceFactory.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Navigation; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript +{ + [ExportLanguageServiceFactory(typeof(IGoToDefinitionService), InternalLanguageNames.TypeScript), Shared] + internal sealed class VSTypeScriptGoToDefinitionServiceFactory : ILanguageServiceFactory + { + private readonly IVSTypeScriptGoToDefinitionServiceFactoryImplementation _impl; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public VSTypeScriptGoToDefinitionServiceFactory(IVSTypeScriptGoToDefinitionServiceFactoryImplementation impl) + => _impl = impl; + + public ILanguageService CreateLanguageService(HostLanguageServices languageServices) + => new ServiceWrapper(_impl.CreateLanguageService(languageServices)); + + private sealed class ServiceWrapper : IGoToDefinitionService + { + private readonly IVSTypeScriptGoToDefinitionService _service; + + public ServiceWrapper(IVSTypeScriptGoToDefinitionService service) + => _service = service; + + public async Task?> FindDefinitionsAsync(Document document, int position, CancellationToken cancellationToken) + { + var items = await _service.FindDefinitionsAsync(document, position, cancellationToken).ConfigureAwait(false); + return items.Select(item => new VSTypeScriptNavigableItemWrapper(item)); + } + + public bool TryGoToDefinition(Document document, int position, CancellationToken cancellationToken) + => _service.TryGoToDefinition(document, position, cancellationToken); + } + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptGoToSymbolService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptGoToSymbolService.cs new file mode 100644 index 0000000000000..51eb2a888996a --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptGoToSymbolService.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.GoToDefinition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript +{ + [ExportLanguageService(typeof(IGoToSymbolService), InternalLanguageNames.TypeScript), Shared] + internal sealed class VSTypeScriptGoToSymbolService : IGoToSymbolService + { + private readonly IVSTypeScriptGoToSymbolServiceImplementation _impl; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public VSTypeScriptGoToSymbolService(IVSTypeScriptGoToSymbolServiceImplementation impl) + => _impl = impl; + + public Task GetSymbolsAsync(GoToSymbolContext context) + => _impl.GetSymbolsAsync(new VSTypeScriptGoToSymbolContext(context)); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptNavigationBarItemService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptNavigationBarItemService.cs index 4c71a20ca40d9..9830629f086e6 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptNavigationBarItemService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptNavigationBarItemService.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Navigation; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Roslyn.Utilities; @@ -52,10 +53,8 @@ public async Task TryNavigateToItemAsync( await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var workspace = document.Project.Solution.Workspace; - var navigationService = VSTypeScriptDocumentNavigationServiceWrapper.Create(workspace); - navigationService.TryNavigateToPosition( - workspace, document.Id, navigationSpan.Start, - virtualSpace: 0, options: null, cancellationToken: cancellationToken); + var navigationService = workspace.Services.GetRequiredService(); + navigationService.TryNavigateToPosition(workspace, document.Id, navigationSpan.Start, virtualSpace: 0, NavigationOptions.Default, cancellationToken); return true; } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptStreamingFindUsagesPresenterAccessor.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptStreamingFindUsagesPresenterAccessor.cs new file mode 100644 index 0000000000000..503284f5d06dc --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptStreamingFindUsagesPresenterAccessor.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.Composition; +using System.Threading; +using Microsoft.CodeAnalysis.Editor.Host; +using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript +{ + [Export(typeof(IVSTypeScriptStreamingFindUsagesPresenterAccessor)), Shared] + internal sealed class VSTypeScriptStreamingFindUsagesPresenterAccessor : IVSTypeScriptStreamingFindUsagesPresenterAccessor + { + private readonly IStreamingFindUsagesPresenter _underlyingObject; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public VSTypeScriptStreamingFindUsagesPresenterAccessor(IStreamingFindUsagesPresenter underlyingObject) + => _underlyingObject = underlyingObject; + + public (IVSTypeScriptFindUsagesContext context, CancellationToken cancellationToken) StartSearch( + string title, bool supportsReferences) + { + var (context, cancellationToken) = _underlyingObject.StartSearch(title, supportsReferences); + return (new VSTypeScriptFindUsagesContext(context), cancellationToken); + } + + public void ClearAll() + => _underlyingObject.ClearAll(); + } +} diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptStreamingProgressTracker.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptStreamingProgressTracker.cs new file mode 100644 index 0000000000000..788798ceb7d24 --- /dev/null +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptStreamingProgressTracker.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; +using Microsoft.CodeAnalysis.Shared.Utilities; + +namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript +{ + internal sealed class VSTypeScriptStreamingProgressTracker : IVSTypeScriptStreamingProgressTracker + { + private readonly IStreamingProgressTracker _progressTracker; + + public VSTypeScriptStreamingProgressTracker(IStreamingProgressTracker progressTracker) + { + _progressTracker = progressTracker; + } + + public ValueTask AddItemsAsync(int count, CancellationToken cancellationToken) + => _progressTracker.AddItemsAsync(count, cancellationToken); + + public ValueTask ItemCompletedAsync(CancellationToken cancellationToken) + => _progressTracker.ItemCompletedAsync(cancellationToken); + } +} diff --git a/src/EditorFeatures/Core/FindReferences/FindReferencesCommandHandler.cs b/src/EditorFeatures/Core/FindReferences/FindReferencesCommandHandler.cs index b7c79db5a3fd2..95e74bf97c2a6 100644 --- a/src/EditorFeatures/Core/FindReferences/FindReferencesCommandHandler.cs +++ b/src/EditorFeatures/Core/FindReferences/FindReferencesCommandHandler.cs @@ -8,11 +8,12 @@ using System.ComponentModel.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; @@ -30,7 +31,7 @@ namespace Microsoft.CodeAnalysis.Editor.FindReferences internal class FindReferencesCommandHandler : ICommandHandler { private readonly IStreamingFindUsagesPresenter _streamingPresenter; - + private readonly IGlobalOptionService _globalOptions; private readonly IAsynchronousOperationListener _asyncListener; public string DisplayName => EditorFeaturesResources.Find_References; @@ -39,11 +40,13 @@ internal class FindReferencesCommandHandler : ICommandHandler throw new NotImplementedException(); +#pragma warning restore IDE0060 // Remove unused parameter + } +} diff --git a/src/EditorFeatures/Core/FindUsages/SimpleFindUsagesContext.cs b/src/EditorFeatures/Core/FindUsages/SimpleFindUsagesContext.cs index 6adc1175310ee..8be625c226bb8 100644 --- a/src/EditorFeatures/Core/FindUsages/SimpleFindUsagesContext.cs +++ b/src/EditorFeatures/Core/FindUsages/SimpleFindUsagesContext.cs @@ -8,30 +8,37 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.FindUsages +namespace Microsoft.CodeAnalysis.FindUsages { /// /// Simple implementation of a that just aggregates the results /// for consumers that just want the data once it is finally computed. /// - internal class SimpleFindUsagesContext : FindUsagesContext + internal sealed class SimpleFindUsagesContext : FindUsagesContext { private readonly object _gate = new(); + private readonly IGlobalOptionService _globalOptions; + private readonly ImmutableArray.Builder _definitionItems = ImmutableArray.CreateBuilder(); private readonly ImmutableArray.Builder _referenceItems = ImmutableArray.CreateBuilder(); - public SimpleFindUsagesContext() + public SimpleFindUsagesContext(IGlobalOptionService globalOptions) { + _globalOptions = globalOptions; } public string Message { get; private set; } public string SearchTitle { get; private set; } + public override ValueTask GetOptionsAsync(string language, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetFindUsagesOptions(language)); + public override ValueTask ReportMessageAsync(string message, CancellationToken cancellationToken) { Message = message; diff --git a/src/EditorFeatures/Core/GoToBase/GoToBaseCommandHandler.cs b/src/EditorFeatures/Core/GoToBase/GoToBaseCommandHandler.cs index c3d57a49be004..745de225fd56c 100644 --- a/src/EditorFeatures/Core/GoToBase/GoToBaseCommandHandler.cs +++ b/src/EditorFeatures/Core/GoToBase/GoToBaseCommandHandler.cs @@ -6,24 +6,26 @@ using System.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.CommandHandlers; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Utilities; using VSCommanding = Microsoft.VisualStudio.Commanding; -namespace Microsoft.CodeAnalysis.Editor.GoToBase +namespace Microsoft.CodeAnalysis.GoToBase { [Export(typeof(VSCommanding.ICommandHandler))] [ContentType(ContentTypeNames.RoslynContentType)] [Name(PredefinedCommandHandlerNames.GoToBase)] - internal class GoToBaseCommandHandler : AbstractGoToCommandHandler + internal sealed class GoToBaseCommandHandler : AbstractGoToCommandHandler { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -31,11 +33,13 @@ public GoToBaseCommandHandler( IThreadingContext threadingContext, IStreamingFindUsagesPresenter streamingPresenter, IUIThreadOperationExecutor uiThreadOperationExecutor, - IAsynchronousOperationListenerProvider listenerProvider) + IAsynchronousOperationListenerProvider listenerProvider, + IGlobalOptionService globalOptions) : base(threadingContext, streamingPresenter, uiThreadOperationExecutor, - listenerProvider.GetListener(FeatureAttribute.GoToBase)) + listenerProvider.GetListener(FeatureAttribute.GoToBase), + globalOptions) { } @@ -44,8 +48,8 @@ public GoToBaseCommandHandler( protected override string ScopeDescription => EditorFeaturesResources.Locating_bases; protected override FunctionId FunctionId => FunctionId.CommandHandler_GoToBase; - protected override Task FindActionAsync(Document document, int caretPosition, IFindUsagesContext context, CancellationToken cancellationToken) + protected override Task FindActionAsync(IFindUsagesContext context, Document document, int caretPosition, CancellationToken cancellationToken) => document.GetRequiredLanguageService() - .FindBasesAsync(document, caretPosition, context, cancellationToken); + .FindBasesAsync(context, document, caretPosition, cancellationToken); } } diff --git a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToDefinitionService.cs b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToDefinitionService.cs index aab0063b8d5c7..bbd428b45b0aa 100644 --- a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToDefinitionService.cs +++ b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToDefinitionService.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindUsages; @@ -48,9 +47,7 @@ private static bool TryNavigateToSpan(Document document, int position, Cancellat var workspace = solution.Workspace; var service = workspace.Services.GetRequiredService(); - var options = solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true); - options = options.WithChangedOption(NavigationOptions.ActivateTab, true); - + var options = new NavigationOptions(PreferProvisionalTab: true, ActivateTab: true); return service.TryNavigateToPosition(workspace, document.Id, position, virtualSpace: 0, options, cancellationToken); } @@ -137,7 +134,7 @@ private bool TryGoToAlternativeLocationIfAlreadyOnDefinition( private static bool IsThirdPartyNavigationAllowed(ISymbol symbolToNavigateTo, int caretPosition, Document document, CancellationToken cancellationToken) { - var syntaxRoot = document.GetSyntaxRootSynchronously(cancellationToken); + var syntaxRoot = document.GetRequiredSyntaxRootSynchronously(cancellationToken); var syntaxFactsService = document.GetRequiredLanguageService(); var containingTypeDeclaration = syntaxFactsService.GetContainingTypeDeclaration(syntaxRoot, caretPosition); diff --git a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs index 10fe802eb69a2..c92177d100e08 100644 --- a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs +++ b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionCommandHandler.cs @@ -85,7 +85,7 @@ internal static bool TryExecuteCommand(Document document, int caretPosition, IGo return true; } - errorMessage = EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret; + errorMessage = FeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret; } if (errorMessage != null) diff --git a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionHelpers.cs b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionHelpers.cs index 2e05946920eab..f560bae5c506d 100644 --- a/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionHelpers.cs +++ b/src/EditorFeatures/Core/GoToDefinition/GoToDefinitionHelpers.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindSymbols; diff --git a/src/EditorFeatures/Core/GoToDefinition/WellKnownSymbolTypes.cs b/src/EditorFeatures/Core/GoToDefinition/WellKnownSymbolTypes.cs index 3dbcc93bf35b3..5401c9e65f304 100644 --- a/src/EditorFeatures/Core/GoToDefinition/WellKnownSymbolTypes.cs +++ b/src/EditorFeatures/Core/GoToDefinition/WellKnownSymbolTypes.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - namespace Microsoft.CodeAnalysis.Editor.GoToDefinition { - internal class WellKnownSymbolTypes + internal static class WellKnownSymbolTypes { public const string Definition = nameof(Definition); } diff --git a/src/EditorFeatures/Core/GoToImplementation/GoToImplementationCommandHandler.cs b/src/EditorFeatures/Core/GoToImplementation/GoToImplementationCommandHandler.cs index e646ba4a96640..a14288e0c1c93 100644 --- a/src/EditorFeatures/Core/GoToImplementation/GoToImplementationCommandHandler.cs +++ b/src/EditorFeatures/Core/GoToImplementation/GoToImplementationCommandHandler.cs @@ -8,12 +8,12 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.CommandHandlers; using Microsoft.CodeAnalysis.Editor.Commanding.Commands; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Commanding; @@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.Editor.GoToImplementation [Export(typeof(ICommandHandler))] [ContentType(ContentTypeNames.RoslynContentType)] [Name(PredefinedCommandHandlerNames.GoToImplementation)] - internal class GoToImplementationCommandHandler : AbstractGoToCommandHandler + internal sealed class GoToImplementationCommandHandler : AbstractGoToCommandHandler { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -32,11 +32,13 @@ public GoToImplementationCommandHandler( IThreadingContext threadingContext, IStreamingFindUsagesPresenter streamingPresenter, IUIThreadOperationExecutor uiThreadOperationExecutor, - IAsynchronousOperationListenerProvider listenerProvider) + IAsynchronousOperationListenerProvider listenerProvider, + IGlobalOptionService globalOptions) : base(threadingContext, streamingPresenter, uiThreadOperationExecutor, - listenerProvider.GetListener(FeatureAttribute.GoToImplementation)) + listenerProvider.GetListener(FeatureAttribute.GoToImplementation), + globalOptions) { } @@ -45,8 +47,8 @@ public GoToImplementationCommandHandler( protected override string ScopeDescription => EditorFeaturesResources.Locating_implementations; protected override FunctionId FunctionId => FunctionId.CommandHandler_GoToImplementation; - protected override Task FindActionAsync(Document document, int caretPosition, IFindUsagesContext context, CancellationToken cancellationToken) + protected override Task FindActionAsync(IFindUsagesContext context, Document document, int caretPosition, CancellationToken cancellationToken) => document.GetRequiredLanguageService() - .FindImplementationsAsync(document, caretPosition, context, cancellationToken); + .FindImplementationsAsync(context, document, caretPosition, cancellationToken); } } diff --git a/src/EditorFeatures/Core/Host/IStreamingFindReferencesPresenter.cs b/src/EditorFeatures/Core/Host/IStreamingFindReferencesPresenter.cs index 8edc3d7a2c4ac..5f72e402afd32 100644 --- a/src/EditorFeatures/Core/Host/IStreamingFindReferencesPresenter.cs +++ b/src/EditorFeatures/Core/Host/IStreamingFindReferencesPresenter.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Editor.Host @@ -87,7 +88,7 @@ public static async Task TryNavigateToOrPresentItemsAsync( // If we're directly going to a location we need to activate the preview so // that focus follows to the new cursor position. This behavior is expected // because we are only going to navigate once successfully - if (await item.TryNavigateToAsync(workspace, showInPreviewTab: true, activateTab: true, cancellationToken).ConfigureAwait(false)) + if (await item.TryNavigateToAsync(workspace, new NavigationOptions(PreferProvisionalTab: true, ActivateTab: true), cancellationToken).ConfigureAwait(false)) return true; } @@ -104,7 +105,7 @@ public static async Task TryNavigateToOrPresentItemsAsync( // going to a location we need to activate the preview so that focus follows to the new cursor position. return await nonExternalItems[0].TryNavigateToAsync( - workspace, showInPreviewTab: true, activateTab: true, cancellationToken).ConfigureAwait(false); + workspace, new NavigationOptions(PreferProvisionalTab: true, ActivateTab: true), cancellationToken).ConfigureAwait(false); } if (presenter != null) diff --git a/src/EditorFeatures/Core/IInlineRenameService.cs b/src/EditorFeatures/Core/IInlineRenameService.cs index 6f6a43090b113..c144c4db9ef5b 100644 --- a/src/EditorFeatures/Core/IInlineRenameService.cs +++ b/src/EditorFeatures/Core/IInlineRenameService.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; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Rename; namespace Microsoft.CodeAnalysis.Editor { @@ -22,11 +21,11 @@ internal interface IInlineRenameService /// The triggerSpan itself. /// An optional cancellation token. /// The rename session. - InlineRenameSessionInfo StartInlineSession(Document document, TextSpan triggerSpan, CancellationToken cancellationToken = default); + InlineRenameSessionInfo StartInlineSession(Document document, TextSpan triggerSpan, CancellationToken cancellationToken); /// /// Returns the currently active inline session, or null if none is active. /// - IInlineRenameSession ActiveSession { get; } + IInlineRenameSession? ActiveSession { get; } } } diff --git a/src/EditorFeatures/Core/IInlineRenameSession.cs b/src/EditorFeatures/Core/IInlineRenameSession.cs index 474e072c5b03f..bf4d1bb52210b 100644 --- a/src/EditorFeatures/Core/IInlineRenameSession.cs +++ b/src/EditorFeatures/Core/IInlineRenameSession.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Editor { - internal class InlineRenameSessionInfo + internal sealed class InlineRenameSessionInfo { /// /// Whether or not the entity at the selected location can be renamed. diff --git a/src/EditorFeatures/Core/Implementation/AddImports/AbstractAddImportsPasteCommandHandler.cs b/src/EditorFeatures/Core/Implementation/AddImports/AbstractAddImportsPasteCommandHandler.cs index d49e1eb3154d2..c2cb8b262b551 100644 --- a/src/EditorFeatures/Core/Implementation/AddImports/AbstractAddImportsPasteCommandHandler.cs +++ b/src/EditorFeatures/Core/Implementation/AddImports/AbstractAddImportsPasteCommandHandler.cs @@ -3,8 +3,10 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.AddMissingImports; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -123,7 +125,16 @@ private void ExecuteCommandWorker( var addMissingImportsService = document.GetRequiredLanguageService(); #pragma warning disable VSTHRD102 // Implement internal logic asynchronously - var updatedDocument = _threadingContext.JoinableTaskFactory.Run(() => addMissingImportsService.AddMissingImportsAsync(document, textSpan, cancellationToken)); + var updatedDocument = _threadingContext.JoinableTaskFactory.Run(async () => + { + var placement = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + + var options = new AddMissingImportsOptions( + HideAdvancedMembers: _globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, document.Project.Language), + placement); + + return await addMissingImportsService.AddMissingImportsAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); + }); #pragma warning restore VSTHRD102 // Implement internal logic asynchronously if (updatedDocument is null) { diff --git a/src/EditorFeatures/Core/Implementation/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs b/src/EditorFeatures/Core/Implementation/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs index 91cef36c28403..c9306b562bd4b 100644 --- a/src/EditorFeatures/Core/Implementation/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs +++ b/src/EditorFeatures/Core/Implementation/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; @@ -125,7 +126,8 @@ private bool TryStart(CancellationToken cancellationToken) var contextAfterStart = GetBraceCompletionContext(); if (contextAfterStart != null) { - var changesAfterStart = _service.GetTextChangesAfterCompletionAsync(contextAfterStart.Value, cancellationToken).WaitAndGetResult(cancellationToken); + var options = IndentationOptions.FromDocumentAsync(contextAfterStart.Value.Document, cancellationToken).WaitAndGetResult(cancellationToken); + var changesAfterStart = _service.GetTextChangesAfterCompletionAsync(contextAfterStart.Value, options, cancellationToken).WaitAndGetResult(cancellationToken); if (changesAfterStart != null) { ApplyBraceCompletionResult(changesAfterStart.Value); @@ -283,8 +285,8 @@ public void PostReturn() return; } - var documentOptions = context.Value.Document.GetOptionsAsync().WaitAndGetResult(CancellationToken.None); - var changesAfterReturn = _service.GetTextChangeAfterReturnAsync(context.Value, documentOptions, CancellationToken.None).WaitAndGetResult(CancellationToken.None); + var options = IndentationOptions.FromDocumentAsync(context.Value.Document, CancellationToken.None).WaitAndGetResult(CancellationToken.None); + var changesAfterReturn = _service.GetTextChangeAfterReturnAsync(context.Value, options, CancellationToken.None).WaitAndGetResult(CancellationToken.None); if (changesAfterReturn != null) { using var caretPreservingTransaction = new CaretPreservingEditTransaction(EditorFeaturesResources.Brace_Completion, _undoHistory, _editorOperations); diff --git a/src/EditorFeatures/Core/Implementation/Classification/ClassificationTypeDefinitions.cs b/src/EditorFeatures/Core/Implementation/Classification/ClassificationTypeDefinitions.cs index cbf993aad2582..264282140ae6e 100644 --- a/src/EditorFeatures/Core/Implementation/Classification/ClassificationTypeDefinitions.cs +++ b/src/EditorFeatures/Core/Implementation/Classification/ClassificationTypeDefinitions.cs @@ -278,6 +278,65 @@ internal sealed class ClassificationTypeDefinitions [Name(ClassificationTypeNames.RegexGrouping)] [BaseDefinition(PredefinedClassificationTypeNames.FormalLanguage)] internal readonly ClassificationTypeDefinition RegexGroupingTypeDefinition; + + #endregion + + #region JSON + [Export] + [Name(ClassificationTypeNames.JsonComment)] + [BaseDefinition(PredefinedClassificationTypeNames.Comment)] + internal readonly ClassificationTypeDefinition JsonCommentTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonNumber)] + [BaseDefinition(PredefinedClassificationTypeNames.Number)] + internal readonly ClassificationTypeDefinition JsonNumberTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonString)] + [BaseDefinition(PredefinedClassificationTypeNames.String)] + internal readonly ClassificationTypeDefinition JsonStringTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonKeyword)] + [BaseDefinition(PredefinedClassificationTypeNames.Keyword)] + internal readonly ClassificationTypeDefinition JsonKeywordTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonText)] + [BaseDefinition(PredefinedClassificationTypeNames.Text)] + internal readonly ClassificationTypeDefinition JsonTextTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonOperator)] + [BaseDefinition(PredefinedClassificationTypeNames.Operator)] + internal readonly ClassificationTypeDefinition JsonOperatorTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonPunctuation)] + [BaseDefinition(PredefinedClassificationTypeNames.Punctuation)] + internal readonly ClassificationTypeDefinition JsonPunctuationTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonArray)] + [BaseDefinition(PredefinedClassificationTypeNames.Punctuation)] + internal readonly ClassificationTypeDefinition JsonArrayTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonObject)] + [BaseDefinition(PredefinedClassificationTypeNames.Punctuation)] + internal readonly ClassificationTypeDefinition JsonObjectTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonPropertyName)] + [BaseDefinition(ClassificationTypeNames.MethodName)] + internal readonly ClassificationTypeDefinition JsonPropertyNameTypeDefinition; + + [Export] + [Name(ClassificationTypeNames.JsonConstructorName)] + [BaseDefinition(ClassificationTypeNames.StructName)] + internal readonly ClassificationTypeDefinition JsonConstructorNameTypeDefinition; + #endregion #region VB XML Literals - Attribute Name diff --git a/src/EditorFeatures/Core/Implementation/Classification/SyntacticClassificationTaggerProvider.TagComputer.cs b/src/EditorFeatures/Core/Implementation/Classification/SyntacticClassificationTaggerProvider.TagComputer.cs index b2e11e59f64d8..92fbec8040e6a 100644 --- a/src/EditorFeatures/Core/Implementation/Classification/SyntacticClassificationTaggerProvider.TagComputer.cs +++ b/src/EditorFeatures/Core/Implementation/Classification/SyntacticClassificationTaggerProvider.TagComputer.cs @@ -90,7 +90,7 @@ public TagComputer( _typeMap = typeMap; _diffTimeout = diffTimeout; _workQueue = new AsyncBatchingWorkQueue( - TimeSpan.FromMilliseconds(TaggerConstants.NearImmediateDelay), + DelayTimeSpan.NearImmediate, ProcessChangesAsync, equalityComparer: null, asyncListener, diff --git a/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionEditHandlerService.cs b/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionEditHandlerService.cs index 8c2bd5db824d8..b605c92aa5a3c 100644 --- a/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionEditHandlerService.cs +++ b/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionEditHandlerService.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.Notification; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; diff --git a/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsStorage.cs b/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsStorage.cs new file mode 100644 index 0000000000000..bc5363d278095 --- /dev/null +++ b/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsStorage.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.SymbolSearch; + +namespace Microsoft.CodeAnalysis.CodeActions +{ + internal static class CodeActionOptionsStorage + { + internal static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, string language, bool isBlocking) + => new( + SearchOptions: globalOptions.GetSymbolSearchOptions(language), + HideAdvancedMembers: globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, language), + IsBlocking: isBlocking); + } +} diff --git a/src/EditorFeatures/Core/Implementation/CodeDefinitionWindow/DefinitionContextTracker.cs b/src/EditorFeatures/Core/Implementation/CodeDefinitionWindow/DefinitionContextTracker.cs index 44a4f4fa7c36e..e1e1059e5944b 100644 --- a/src/EditorFeatures/Core/Implementation/CodeDefinitionWindow/DefinitionContextTracker.cs +++ b/src/EditorFeatures/Core/Implementation/CodeDefinitionWindow/DefinitionContextTracker.cs @@ -10,12 +10,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.GoToDefinition; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Navigation; diff --git a/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractDiagnosticsAdornmentTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractDiagnosticsAdornmentTaggerProvider.cs index 44f15bd41d844..8c3d5b44fb93b 100644 --- a/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractDiagnosticsAdornmentTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractDiagnosticsAdornmentTaggerProvider.cs @@ -54,12 +54,14 @@ protected static object CreateToolTipContent(Workspace workspace, DiagnosticData { Action? navigationAction = null; string? tooltip = null; - if (workspace is object - && diagnostic.HelpLink is { } helpLink - && Uri.TryCreate(helpLink, UriKind.Absolute, out var helpLinkUri)) + if (workspace != null) { - navigationAction = new QuickInfoHyperLink(workspace, helpLinkUri).NavigationAction; - tooltip = helpLink; + var helpLinkUri = diagnostic.GetValidHelpLinkUri(); + if (helpLinkUri != null) + { + navigationAction = new QuickInfoHyperLink(workspace, helpLinkUri).NavigationAction; + tooltip = diagnostic.HelpLink; + } } var diagnosticIdTextRun = navigationAction is null diff --git a/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractDiagnosticsTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractDiagnosticsTaggerProvider.cs index 337881d45f6f1..e56c13d1d6bc3 100644 --- a/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractDiagnosticsTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractDiagnosticsTaggerProvider.cs @@ -151,8 +151,10 @@ 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, InternalDiagnosticsOptions.NormalDiagnosticMode, cancellationToken); + workspace, document.Project.Id, document.Id, diagnosticMode, cancellationToken); foreach (var bucket in buckets) { @@ -170,11 +172,13 @@ private async Task ProduceTagsAsync( { try { + var diagnosticMode = GlobalOptions.GetDiagnosticMode(InternalDiagnosticsOptions.NormalDiagnosticMode); + var id = bucket.Id; var diagnostics = await _diagnosticService.GetPushDiagnosticsAsync( workspace, document.Project.Id, document.Id, id, includeSuppressedDiagnostics: false, - diagnosticMode: InternalDiagnosticsOptions.NormalDiagnosticMode, + diagnosticMode, cancellationToken).ConfigureAwait(false); var isLiveUpdate = id is ISupportLiveUpdate; diff --git a/src/EditorFeatures/Core/Implementation/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs b/src/EditorFeatures/Core/Implementation/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs index cafc3cca4d9ea..920c78a721360 100644 --- a/src/EditorFeatures/Core/Implementation/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs +++ b/src/EditorFeatures/Core/Implementation/DocumentationComments/AbstractDocumentationCommentCommandHandler.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -94,14 +95,20 @@ private static bool CompleteComment( var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken); var options = DocumentationCommentOptions.From(documentOptions); - var snippet = getSnippetAction(service, syntaxTree, text, caretPosition, options, cancellationToken); - if (snippet != null) + // 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) { - ApplySnippet(snippet, subjectBuffer, textView); - return true; + var snippet = getSnippetAction(service, syntaxTree, text, snapshot.Span.Start, options, cancellationToken); + if (snippet != null) + { + ApplySnippet(snippet, subjectBuffer, textView); + returnValue = true; + } } - return false; + return returnValue; } public CommandState GetCommandState(TypeCharCommandArgs args, Func nextHandler) diff --git a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueLanguageService.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueLanguageService.cs index bab37ec4f33eb..fc26794701023 100644 --- a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueLanguageService.cs +++ b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueLanguageService.cs @@ -126,7 +126,7 @@ public async ValueTask EnterBreakStateAsync(CancellationToken cancellationToken) try { - await session.BreakStateOrCapabilitiesChangedAsync(_diagnosticService, inBreakState: true, cancellationToken).ConfigureAwait(false); + await session.BreakStateOrCapabilitiesChangedAsync(_diagnosticService, _diagnosticUpdateSource, inBreakState: true, cancellationToken).ConfigureAwait(false); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { @@ -150,7 +150,7 @@ public async ValueTask ExitBreakStateAsync(CancellationToken cancellationToken) try { - await session.BreakStateOrCapabilitiesChangedAsync(_diagnosticService, inBreakState: false, cancellationToken).ConfigureAwait(false); + await session.BreakStateOrCapabilitiesChangedAsync(_diagnosticService, _diagnosticUpdateSource, inBreakState: false, cancellationToken).ConfigureAwait(false); GetActiveStatementTrackingService().EndTracking(); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) @@ -169,7 +169,7 @@ public async ValueTask OnCapabilitiesChangedAsync(CancellationToken cancellation try { - await GetDebuggingSession().BreakStateOrCapabilitiesChangedAsync(_diagnosticService, inBreakState: null, cancellationToken).ConfigureAwait(false); + await GetDebuggingSession().BreakStateOrCapabilitiesChangedAsync(_diagnosticService, _diagnosticUpdateSource, inBreakState: null, cancellationToken).ConfigureAwait(false); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { @@ -293,7 +293,7 @@ public async ValueTask GetHotReloadUpdatesAsync(Cancell _pendingUpdatedSolution = solution; var updates = moduleUpdates.Updates.SelectAsArray( - update => new ManagedHotReloadUpdate(update.Module, update.ILDelta, update.MetadataDelta, update.UpdatedTypes)); + 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); diff --git a/src/EditorFeatures/Core/Implementation/ExtractMethod/AbstractExtractMethodCommandHandler.cs b/src/EditorFeatures/Core/Implementation/ExtractMethod/AbstractExtractMethodCommandHandler.cs index 47ad629348701..844239b9cb464 100644 --- a/src/EditorFeatures/Core/Implementation/ExtractMethod/AbstractExtractMethodCommandHandler.cs +++ b/src/EditorFeatures/Core/Implementation/ExtractMethod/AbstractExtractMethodCommandHandler.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Commanding; diff --git a/src/EditorFeatures/Core/Implementation/Formatting/FormatCommandHandler.Paste.cs b/src/EditorFeatures/Core/Implementation/Formatting/FormatCommandHandler.Paste.cs index 8eacc8339465f..298369acb353b 100644 --- a/src/EditorFeatures/Core/Implementation/Formatting/FormatCommandHandler.Paste.cs +++ b/src/EditorFeatures/Core/Implementation/Formatting/FormatCommandHandler.Paste.cs @@ -47,7 +47,7 @@ public void ExecuteCommand(PasteCommandArgs args, Action nextHandler, CommandExe } } - private static void ExecuteCommandWorker(PasteCommandArgs args, SnapshotPoint? caretPosition, CancellationToken cancellationToken) + private void ExecuteCommandWorker(PasteCommandArgs args, SnapshotPoint? caretPosition, CancellationToken cancellationToken) { if (!caretPosition.HasValue) { @@ -60,12 +60,12 @@ private static void ExecuteCommandWorker(PasteCommandArgs args, SnapshotPoint? c return; } - var solution = document.Project.Solution; - if (!solution.Options.GetOption(FormattingBehaviorOptions.FormatOnPaste, document.Project.Language)) + if (!_globalOptions.GetOption(FormattingOptionsMetadata.FormatOnPaste, document.Project.Language)) { return; } + var solution = document.Project.Solution; if (!solution.Workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) { return; diff --git a/src/EditorFeatures/Core/Implementation/Formatting/FormatCommandHandler.cs b/src/EditorFeatures/Core/Implementation/Formatting/FormatCommandHandler.cs index f1ccde5c64205..923c9468fba8c 100644 --- a/src/EditorFeatures/Core/Implementation/Formatting/FormatCommandHandler.cs +++ b/src/EditorFeatures/Core/Implementation/Formatting/FormatCommandHandler.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; @@ -42,6 +43,7 @@ internal partial class FormatCommandHandler : { private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; + private readonly IGlobalOptionService _globalOptions; public string DisplayName => EditorFeaturesResources.Automatic_Formatting; @@ -49,10 +51,12 @@ internal partial class FormatCommandHandler : [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public FormatCommandHandler( ITextUndoHistoryRegistry undoHistoryRegistry, - IEditorOperationsFactoryService editorOperationsFactoryService) + IEditorOperationsFactoryService editorOperationsFactoryService, + IGlobalOptionService globalOptions) { _undoHistoryRegistry = undoHistoryRegistry; _editorOperationsFactoryService = editorOperationsFactoryService; + _globalOptions = globalOptions; } private void Format(ITextView textView, Document document, TextSpan? selectionOpt, CancellationToken cancellationToken) @@ -162,7 +166,8 @@ private void ExecuteReturnOrTypeCommandWorker(EditorCommandArgs args, Cancellati } else if (args is TypeCharCommandArgs typeCharArgs) { - if (!service.SupportsFormattingOnTypedCharacter(document, typeCharArgs.TypedChar)) + var options = AutoFormattingOptions.From(document.Project); + if (!service.SupportsFormattingOnTypedCharacter(document, options, typeCharArgs.TypedChar)) { return; } diff --git a/src/Features/Core/Portable/Navigation/NavigationOptionsProvider.cs b/src/EditorFeatures/Core/Implementation/Formatting/FormattingOptionsMetadata.cs similarity index 55% rename from src/Features/Core/Portable/Navigation/NavigationOptionsProvider.cs rename to src/EditorFeatures/Core/Implementation/Formatting/FormattingOptionsMetadata.cs index 6b3ed191919cb..9c607691ff476 100644 --- a/src/Features/Core/Portable/Navigation/NavigationOptionsProvider.cs +++ b/src/EditorFeatures/Core/Implementation/Formatting/FormattingOptionsMetadata.cs @@ -9,18 +9,24 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; -namespace Microsoft.CodeAnalysis.Navigation +namespace Microsoft.CodeAnalysis.Editor.Implementation.Formatting { [ExportSolutionOptionProvider, Shared] - internal class NavigationOptionsProvider : IOptionProvider + internal sealed class FormattingOptionsMetadata : IOptionProvider { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public NavigationOptionsProvider() + public FormattingOptionsMetadata() { } public ImmutableArray Options { get; } = ImmutableArray.Create( - NavigationOptions.PreferProvisionalTab); + FormatOnPaste); + + private const string FeatureName = "FormattingOptions"; + + public static readonly PerLanguageOption2 FormatOnPaste = + new(FeatureName, OptionGroup.Default, "FormatOnPaste", defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.FormatOnPaste")); } } diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.FailureInlineRenameInfo.cs b/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.FailureInlineRenameInfo.cs index 5be670ca869ec..fad7ccdab55e3 100644 --- a/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.FailureInlineRenameInfo.cs +++ b/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.FailureInlineRenameInfo.cs @@ -9,13 +9,16 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { internal abstract partial class AbstractEditorInlineRenameService { - private class FailureInlineRenameInfo : IInlineRenameInfo + internal static readonly IInlineRenameInfo DefaultFailureInfo = new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element); + + private sealed class FailureInlineRenameInfo : IInlineRenameInfo { public FailureInlineRenameInfo(string localizedErrorMessage) => this.LocalizedErrorMessage = localizedErrorMessage; @@ -24,7 +27,7 @@ public FailureInlineRenameInfo(string localizedErrorMessage) public bool HasOverloads => false; - public bool ForceRenameOverloads => false; + public bool MustRenameOverloads => false; public string LocalizedErrorMessage { get; } @@ -44,7 +47,7 @@ public FailureInlineRenameInfo(string localizedErrorMessage) public TextSpan? GetConflictEditSpan(InlineRenameLocation location, string triggerText, string replacementText, CancellationToken cancellationToken) => null; - public Task FindRenameLocationsAsync(OptionSet optionSet, CancellationToken cancellationToken) => Task.FromResult(null); + public Task FindRenameLocationsAsync(SymbolRenameOptions options, CancellationToken cancellationToken) => Task.FromResult(null); public bool TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) => false; diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs b/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs index 986d9c71496e6..45b1faf47c43f 100644 --- a/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs +++ b/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.InlineRenameLocationSet.cs @@ -37,7 +37,7 @@ private InlineRenameLocation ConvertLocation(RenameLocation location) _renameLocationSet.Solution.GetDocument(location.DocumentId), location.Location.SourceSpan); } - public async Task GetReplacementsAsync(string replacementText, OptionSet optionSet, CancellationToken cancellationToken) + public async Task GetReplacementsAsync(string replacementText, SymbolRenameOptions options, CancellationToken cancellationToken) { var conflicts = await _renameLocationSet.ResolveConflictsAsync( _renameInfo.GetFinalSymbolName(replacementText), nonConflictSymbols: null, cancellationToken: cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs b/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs index 2f1703c3ca11b..ebd6da878165f 100644 --- a/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs +++ b/src/EditorFeatures/Core/Implementation/InlineRename/AbstractEditorInlineRenameService.SymbolRenameInfo.cs @@ -42,7 +42,7 @@ private partial class SymbolInlineRenameInfo : IInlineRenameInfoWithFileRename public string? LocalizedErrorMessage { get; } public TextSpan TriggerSpan { get; } public bool HasOverloads { get; } - public bool ForceRenameOverloads { get; } + public bool MustRenameOverloads { get; } /// /// The locations of the potential rename candidates for the symbol. @@ -68,7 +68,7 @@ public SymbolInlineRenameInfo( this.RenameSymbol = renameSymbol; this.HasOverloads = RenameLocations.GetOverloadedSymbols(this.RenameSymbol).Any(); - this.ForceRenameOverloads = forceRenameOverloads; + this.MustRenameOverloads = forceRenameOverloads; _isRenamingAttributePrefix = CanRenameAttributePrefix(triggerText); this.TriggerSpan = GetReferenceEditSpan(new InlineRenameLocation(document, triggerSpan), triggerText, cancellationToken); @@ -183,11 +183,11 @@ public string GetFinalSymbolName(string replacementText) return replacementText; } - public async Task FindRenameLocationsAsync(OptionSet? optionSet, CancellationToken cancellationToken) + public async Task FindRenameLocationsAsync(SymbolRenameOptions options, CancellationToken cancellationToken) { var solution = _document.Project.Solution; var locations = await Renamer.FindRenameLocationsAsync( - solution, this.RenameSymbol, RenameOptionSet.From(solution, optionSet), cancellationToken).ConfigureAwait(false); + solution, this.RenameSymbol, options, cancellationToken).ConfigureAwait(false); return new InlineRenameLocationSet(this, locations); } diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs b/src/EditorFeatures/Core/Implementation/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs index cfb5a35631938..822784904259d 100644 --- a/src/EditorFeatures/Core/Implementation/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs +++ b/src/EditorFeatures/Core/Implementation/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs @@ -7,6 +7,7 @@ using System.Linq; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Notification; +using Microsoft.CodeAnalysis.Rename; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/IEditorInlineRenameService.cs b/src/EditorFeatures/Core/Implementation/InlineRename/IEditorInlineRenameService.cs index 00e0deafb732b..9975fffe79d83 100644 --- a/src/EditorFeatures/Core/Implementation/InlineRename/IEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/Implementation/InlineRename/IEditorInlineRenameService.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Rename.ConflictEngine; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -149,7 +150,7 @@ internal interface IInlineRenameLocationSet /// and TextSpan in the original solution, and specify their new span and possible conflict /// resolution. /// - Task GetReplacementsAsync(string replacementText, OptionSet optionSet, CancellationToken cancellationToken); + Task GetReplacementsAsync(string replacementText, SymbolRenameOptions options, CancellationToken cancellationToken); } internal interface IInlineRenameInfo @@ -176,9 +177,9 @@ internal interface IInlineRenameInfo bool HasOverloads { get; } /// - /// Whether the Rename Overloads option should be forced to true. Used if rename is invoked from within a nameof expression. + /// True if overloads must be renamed (the user is not given a choice). Used if rename is invoked from within a nameof expression. /// - bool ForceRenameOverloads { get; } + bool MustRenameOverloads { get; } /// /// The short name of the symbol being renamed, for use in displaying information to the user. @@ -225,7 +226,7 @@ internal interface IInlineRenameInfo /// multiple times. For example, this can be called one time for the initial set of /// locations to rename, as well as any time the rename options are changed by the user. /// - Task FindRenameLocationsAsync(OptionSet optionSet, CancellationToken cancellationToken); + Task FindRenameLocationsAsync(SymbolRenameOptions options, CancellationToken cancellationToken); /// /// Called before the rename is applied to the specified documents in the workspace. Return @@ -249,6 +250,8 @@ internal interface IInlineRenameInfoWithFileRename : IInlineRenameInfo InlineRenameFileRenameInfo GetFileRenameInfo(); } +#nullable enable + /// /// Language service that allows a language to participate in the editor's inline rename feature. /// diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameService.cs b/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameService.cs index f548aeca1a891..41d1fa0766be5 100644 --- a/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameService.cs +++ b/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameService.cs @@ -6,10 +6,12 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.Threading; -using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.InlineRename; using Microsoft.CodeAnalysis.Navigation; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; @@ -22,7 +24,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { [Export(typeof(IInlineRenameService))] [Export(typeof(InlineRenameService))] - internal class InlineRenameService : IInlineRenameService + internal sealed class InlineRenameService : IInlineRenameService { private readonly IThreadingContext _threadingContext; private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; @@ -33,6 +35,8 @@ internal class InlineRenameService : IInlineRenameService private readonly IFeatureServiceFactory _featureServiceFactory; private InlineRenameSession? _activeRenameSession; + internal readonly IGlobalOptionService GlobalOptions; + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public InlineRenameService( @@ -41,6 +45,7 @@ public InlineRenameService( ITextBufferAssociatedViewService textBufferAssociatedViewService, ITextBufferFactoryService textBufferFactoryService, IFeatureServiceFactory featureServiceFactory, + IGlobalOptionService globalOptions, [ImportMany] IEnumerable refactorNotifyServices, IAsynchronousOperationListenerProvider listenerProvider) { @@ -51,6 +56,7 @@ public InlineRenameService( _featureServiceFactory = featureServiceFactory; _refactorNotifyServices = refactorNotifyServices; _asyncListener = listenerProvider.GetListener(FeatureAttribute.Rename); + GlobalOptions = globalOptions; } public InlineRenameSessionInfo StartInlineSession( @@ -80,12 +86,22 @@ public InlineRenameSessionInfo StartInlineSession( var snapshot = document.GetTextSynchronously(cancellationToken).FindCorrespondingEditorTextSnapshot(); Contract.ThrowIfNull(snapshot, "The document used for starting the inline rename session should still be open and associated with a snapshot."); + var options = new SymbolRenameOptions( + RenameOverloads: renameInfo.MustRenameOverloads || GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameOverloads), + RenameInStrings: GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameInStrings), + RenameInComments: GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameInComments), + RenameFile: GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameFile)); + + var previewChanges = GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.PreviewChanges); + ActiveSession = new InlineRenameSession( _threadingContext, this, document.Project.Solution.Workspace, renameInfo.TriggerSpan.ToSnapshotSpan(snapshot), renameInfo, + options, + previewChanges, _uiThreadOperationExecutor, _textBufferAssociatedViewService, _textBufferFactoryService, diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSession.cs index e6d5c5db25816..862b898c542a5 100644 --- a/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSession.cs @@ -37,7 +37,6 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename internal partial class InlineRenameSession : ForegroundThreadAffinitizedObject, IInlineRenameSession, IFeatureController { private readonly Workspace _workspace; - private readonly InlineRenameService _renameService; private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; private readonly ITextBufferAssociatedViewService _textBufferAssociatedViewService; private readonly ITextBufferFactoryService _textBufferFactoryService; @@ -50,10 +49,13 @@ internal partial class InlineRenameSession : ForegroundThreadAffinitizedObject, private readonly ITextView _triggerView; private readonly IDisposable _inlineRenameSessionDurationLogBlock; + public readonly InlineRenameService RenameService; + private bool _dismissed; private bool _isApplyingEdit; private string _replacementText; - private OptionSet _optionSet; + private SymbolRenameOptions _options; + private bool _previewChanges; private readonly Dictionary _openTextBuffers = new Dictionary(); /// @@ -115,6 +117,8 @@ public InlineRenameSession( Workspace workspace, SnapshotSpan triggerSpan, IInlineRenameInfo renameInfo, + SymbolRenameOptions options, + bool previewChanges, IUIThreadOperationExecutor uiThreadOperationExecutor, ITextBufferAssociatedViewService textBufferAssociatedViewService, ITextBufferFactoryService textBufferFactoryService, @@ -145,16 +149,15 @@ public InlineRenameSession( _featureService = featureServiceFactory.GlobalFeatureService; _completionDisabledToken = _featureService.Disable(PredefinedEditorFeatureNames.Completion, this); - _renameService = renameService; + RenameService = renameService; _uiThreadOperationExecutor = uiThreadOperationExecutor; _refactorNotifyServices = refactorNotifyServices; _asyncListener = asyncListener; _triggerView = textBufferAssociatedViewService.GetAssociatedTextViews(triggerSpan.Snapshot.TextBuffer).FirstOrDefault(v => v.HasAggregateFocus) ?? textBufferAssociatedViewService.GetAssociatedTextViews(triggerSpan.Snapshot.TextBuffer).First(); - _optionSet = renameInfo.ForceRenameOverloads - ? workspace.Options.WithChangedOption(RenameOptions.RenameOverloads, true) - : workspace.Options; + _options = options; + _previewChanges = previewChanges; _initialRenameText = triggerSpan.GetText(); this.ReplacementText = _initialRenameText; @@ -241,7 +244,7 @@ private void InitializeOpenBuffers(SnapshotSpan triggerSpan) _openTextBuffers[triggerSpan.Snapshot.TextBuffer].SetReferenceSpans(SpecializedCollections.SingletonEnumerable(startingSpan.ToTextSpan())); UpdateReferenceLocationsTask(ThreadingContext.JoinableTaskFactory.RunAsync( - () => _renameInfo.FindRenameLocationsAsync(_optionSet, _cancellationTokenSource.Token))); + () => _renameInfo.FindRenameLocationsAsync(_options, _cancellationTokenSource.Token))); RenameTrackingDismisser.DismissRenameTracking(_workspace, _workspace.GetOpenDocumentIds()); } @@ -312,9 +315,10 @@ private void UpdateReferenceLocationsTask(JoinableTask } public Workspace Workspace => _workspace; - public OptionSet OptionSet => _optionSet; + public SymbolRenameOptions Options => _options; + public bool PreviewChanges => _previewChanges; public bool HasRenameOverloads => _renameInfo.HasOverloads; - public bool ForceRenameOverloads => _renameInfo.ForceRenameOverloads; + public bool MustRenameOverloads => _renameInfo.MustRenameOverloads; public IInlineRenameUndoManager UndoManager { get; } @@ -328,31 +332,40 @@ internal OpenTextBufferManager GetBufferManager(ITextBuffer buffer) internal bool TryGetBufferManager(ITextBuffer buffer, out OpenTextBufferManager bufferManager) => _openTextBuffers.TryGetValue(buffer, out bufferManager); - public void RefreshRenameSessionWithOptionsChanged(Option renameOption, bool newValue) + public void RefreshRenameSessionWithOptionsChanged(SymbolRenameOptions newOptions) { + if (_options == newOptions) + { + return; + } + AssertIsForeground(); VerifyNotDismissed(); - // Recompute the result only if the previous result was computed with a different flag - if (_optionSet.GetOption(renameOption) != newValue) + _options = newOptions; + + var cancellationToken = _cancellationTokenSource.Token; + + UpdateReferenceLocationsTask(ThreadingContext.JoinableTaskFactory.RunAsync(async () => { - _optionSet = _optionSet.WithChangedOption(renameOption, newValue); + // 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; - var cancellationToken = _cancellationTokenSource.Token; + return await _renameInfo.FindRenameLocationsAsync(_options, cancellationToken).ConfigureAwait(false); + })); + } - 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; + public void SetPreviewChanges(bool value) + { + AssertIsForeground(); + VerifyNotDismissed(); - return await _renameInfo.FindRenameLocationsAsync(_optionSet, cancellationToken).ConfigureAwait(false); - })); - } + _previewChanges = value; } private void Dismiss(bool rollbackTemporaryEdits) @@ -380,7 +393,7 @@ private void Dismiss(bool rollbackTemporaryEdits) _triggerView.Selection.Clear(); } - _renameService.ActiveSession = null; + RenameService.ActiveSession = null; } private void VerifyNotDismissed() @@ -529,7 +542,7 @@ private void UpdateConflictResolutionTask() } var replacementText = this.ReplacementText; - var optionSet = _optionSet; + var options = _options; var cancellationToken = _conflictResolutionTaskCancellationSource.Token; var asyncToken = _asyncListener.BeginAsyncOperation(nameof(UpdateConflictResolutionTask)); @@ -545,7 +558,7 @@ private void UpdateConflictResolutionTask() var result = await _allRenameLocationsTask.JoinAsync(cancellationToken).ConfigureAwait(false); await TaskScheduler.Default; - return await result.GetReplacementsAsync(replacementText, optionSet, cancellationToken).ConfigureAwait(false); + return await result.GetReplacementsAsync(replacementText, options, cancellationToken).ConfigureAwait(false); }); _conflictResolutionTask.Task.CompletesAsyncOperation(asyncToken); @@ -629,7 +642,7 @@ private void LogRenameSession(RenameLogMessage.UserActionOutcome outcome, bool p var replacementKinds = result.GetAllReplacementKinds().ToList(); Logger.Log(FunctionId.Rename_InlineSession_Session, RenameLogMessage.Create( - _optionSet, + _options, outcome, conflictResolutionFinishedComputing, previewChanges, @@ -639,7 +652,7 @@ private void LogRenameSession(RenameLogMessage.UserActionOutcome outcome, bool p { Debug.Assert(outcome.HasFlag(RenameLogMessage.UserActionOutcome.Canceled)); Logger.Log(FunctionId.Rename_InlineSession_Session, RenameLogMessage.Create( - _optionSet, + _options, outcome, conflictResolutionFinishedComputing, previewChanges, @@ -686,7 +699,7 @@ private bool CommitWorker(bool previewChanges) return false; } - previewChanges = previewChanges || OptionSet.GetOption(RenameOptions.PreviewChanges); + previewChanges = previewChanges || _previewChanges; var result = _uiThreadOperationExecutor.Execute( title: EditorFeaturesResources.Rename, diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSessionOptionsStorage.cs b/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSessionOptionsStorage.cs new file mode 100644 index 0000000000000..f0b883b0becf7 --- /dev/null +++ b/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSessionOptionsStorage.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.InlineRename +{ + internal static class InlineRenameSessionOptionsStorage + { + private const string FeatureName = "InlineRenameSessionOptions"; + + public static readonly Option2 RenameOverloads = new(FeatureName, "RenameOverloads", defaultValue: false, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RenameOverloads")); + public static readonly Option2 RenameInStrings = new(FeatureName, "RenameInStrings", defaultValue: false, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RenameInStrings")); + public static readonly Option2 RenameInComments = new(FeatureName, "RenameInComments", defaultValue: false, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RenameInComments")); + public static readonly Option2 RenameFile = new(FeatureName, "RenameFile", defaultValue: true, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RenameFile")); + public static readonly Option2 PreviewChanges = new(FeatureName, "PreviewChanges", defaultValue: false, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreviewRename")); + } +} diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/RenameLogMessage.cs b/src/EditorFeatures/Core/Implementation/InlineRename/RenameLogMessage.cs index 56516000c5dbe..0588c89660a03 100644 --- a/src/EditorFeatures/Core/Implementation/InlineRename/RenameLogMessage.cs +++ b/src/EditorFeatures/Core/Implementation/InlineRename/RenameLogMessage.cs @@ -29,15 +29,15 @@ internal static class RenameLogMessage private const string UnresolvableConflicts = nameof(UnresolvableConflicts); public static KeyValueLogMessage Create( - OptionSet optionSet, UserActionOutcome outcome, + SymbolRenameOptions options, UserActionOutcome outcome, bool conflictResolutionFinishedComputing, bool previewChanges, IList replacementKinds) { return KeyValueLogMessage.Create(LogType.UserAction, m => { - m[RenameInComments] = optionSet.GetOption(RenameOptions.RenameInComments); - m[RenameInStrings] = optionSet.GetOption(RenameOptions.RenameInStrings); - m[RenameOverloads] = optionSet.GetOption(RenameOptions.RenameOverloads); + m[RenameInComments] = options.RenameInComments; + m[RenameInStrings] = options.RenameInStrings; + m[RenameOverloads] = options.RenameOverloads; m[Committed] = (outcome & UserActionOutcome.Committed) == UserActionOutcome.Committed; m[Canceled] = (outcome & UserActionOutcome.Canceled) == UserActionOutcome.Canceled; diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AbstractController.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AbstractController.cs index f5f84b1c79e00..d701d61c49120 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AbstractController.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AbstractController.cs @@ -7,6 +7,7 @@ using System; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Roslyn.Utilities; @@ -17,6 +18,7 @@ internal abstract class AbstractController where TPresenterSession : IIntelliSensePresenterSession { + protected readonly IGlobalOptionService GlobalOptions; protected readonly ITextView TextView; protected readonly ITextBuffer SubjectBuffer; protected readonly IIntelliSensePresenter Presenter; @@ -32,9 +34,18 @@ internal abstract class AbstractController sessionOpt != null; - protected AbstractController(IThreadingContext threadingContext, ITextView textView, ITextBuffer subjectBuffer, IIntelliSensePresenter presenter, IAsynchronousOperationListener asyncListener, IDocumentProvider documentProvider, string asyncOperationId) + protected AbstractController( + IGlobalOptionService globalOptions, + IThreadingContext threadingContext, + ITextView textView, + ITextBuffer subjectBuffer, + IIntelliSensePresenter presenter, + IAsynchronousOperationListener asyncListener, + IDocumentProvider documentProvider, + string asyncOperationId) : base(threadingContext) { + this.GlobalOptions = globalOptions; this.TextView = textView; this.SubjectBuffer = subjectBuffer; this.Presenter = presenter; diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/AsyncCompletionLogger.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/AsyncCompletionLogger.cs index ddf5677c8b928..ad7f46be609f4 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/AsyncCompletionLogger.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/AsyncCompletionLogger.cs @@ -10,11 +10,25 @@ 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 enum ActionInfo { - // For type import completion + // # of sessions where import completion is enabled by default SessionWithTypeImportCompletionEnabled, + // # of sessions that we wait for import compeltion task to complete before return + // curerntly it's decided by "responsive completion" options + SessionWithImportCompletionBlocking, + // # of sessions where items from import completion are not included intially + SessionWithImportCompletionDelayed, + // # of session among SessionWithImportCompletionDelayed where import completion items + // are later included in list update. Note this doesn't include using of expander. + SessionWithDelayedImportCompletionIncludedInUpdate, + // Among sessions in SessionWithImportCompletionDelayed, how much longer it takes + // for import completion task to finish after regular item task is completed. + // Knowing this would help us to decide whether a short wait would have ensure import completion + // items to be included in the intial list. + AdditionalTicksToCompleteDelayedImportCompletion, ExpanderUsageCount, // For targeted type completion @@ -34,7 +48,24 @@ private enum ActionInfo GetDefaultsMatchTicks, } - internal static void LogSessionWithTypeImportCompletionEnabled() => + internal static void LogImportCompletionGetContext(bool isBlocking, bool delayed) + { + s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithTypeImportCompletionEnabled); + + if (isBlocking) + s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithImportCompletionBlocking); + + if (delayed) + s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithImportCompletionDelayed); + } + + internal static void LogSessionWithDelayedImportCompletionIncludedInUpdate() => + s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithDelayedImportCompletionIncludedInUpdate); + + internal static void LogAdditionalTicksToCompleteDelayedImportCompletionDataPoint(int count) => + s_histogramLogAggregator.IncreaseCount((int)ActionInfo.AdditionalTicksToCompleteDelayedImportCompletion, count); + + internal static void LogDelayedImportCompletionIncluded() => s_logAggregator.IncreaseCount((int)ActionInfo.SessionWithTypeImportCompletionEnabled); internal static void LogExpanderUsage() => @@ -79,6 +110,14 @@ internal static void ReportTelemetry() var mergeInfo = ((ActionInfo)kv.Key).ToString("f"); m[mergeInfo] = 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(); + } })); } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CommitManager.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CommitManager.cs index 7e9e52c4f060a..192290e3d57bf 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CommitManager.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CommitManager.cs @@ -9,10 +9,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Completion.Providers; 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.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -35,6 +35,7 @@ internal sealed class CommitManager : ForegroundThreadAffinitizedObject, IAsyncC private readonly RecentItemsManager _recentItemsManager; private readonly ITextView _textView; + private readonly IGlobalOptionService _globalOptions; public IEnumerable PotentialCommitCharacters { @@ -52,8 +53,10 @@ public IEnumerable PotentialCommitCharacters } } - internal CommitManager(ITextView textView, RecentItemsManager recentItemsManager, IThreadingContext threadingContext) : base(threadingContext) + internal CommitManager(ITextView textView, RecentItemsManager recentItemsManager, IGlobalOptionService globalOptions, IThreadingContext threadingContext) + : base(threadingContext) { + _globalOptions = globalOptions; _recentItemsManager = recentItemsManager; _textView = textView; } @@ -115,11 +118,11 @@ public AsyncCompletionData.CommitResult TryCommit( return new AsyncCompletionData.CommitResult(isHandled: true, AsyncCompletionData.CommitBehavior.CancelCommit); } - var options = CompletionOptions.From(document.Project); + var options = _globalOptions.GetCompletionOptions(document.Project.Language); var serviceRules = completionService.GetRules(options); // We can be called before for ShouldCommitCompletion. However, that call does not provide rules applied for the completion item. - // Now we check for the commit charcter in the context of Rules that could change the list of commit characters. + // Now we check for the commit character in the context of Rules that could change the list of commit characters. if (!Helpers.IsStandardCommitCharacter(typeChar) && !IsCommitCharacter(serviceRules, roslynItem, typeChar)) { @@ -198,7 +201,7 @@ private AsyncCompletionData.CommitResult Commit( CompletionChange change; - // We met an issue when external code threw an OperationCanceledException and the cancellationToken is not cancelled. + // We met an issue when external code threw an OperationCanceledException and the cancellationToken is not canceled. // Catching this scenario for further investigations. // See https://github.com/dotnet/roslyn/issues/38455. try @@ -241,7 +244,7 @@ private AsyncCompletionData.CommitResult Commit( if (change.NewPosition.HasValue) { - // Roslyn knows how to positionate the caret in the snapshot we just created. + // 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)); } @@ -271,7 +274,7 @@ private AsyncCompletionData.CommitResult Commit( 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 snapsot defined above. + // 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(); @@ -312,7 +315,7 @@ private AsyncCompletionData.CommitResult Commit( internal static bool IsCommitCharacter(CompletionRules completionRules, CompletionItem item, char ch) { - // First see if the item has any specifc commit rules it wants followed. + // First see if the item has any specific commit rules it wants followed. foreach (var rule in item.Rules.CommitCharacterRules) { switch (rule.Kind) diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CommitManagerProvider.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CommitManagerProvider.cs index e8bb5daa0c909..0e3bd7e6af515 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CommitManagerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CommitManagerProvider.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; @@ -20,13 +21,15 @@ internal class CommitManagerProvider : IAsyncCompletionCommitManagerProvider { private readonly IThreadingContext _threadingContext; private readonly RecentItemsManager _recentItemsManager; + private readonly IGlobalOptionService _globalOptions; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CommitManagerProvider(IThreadingContext threadingContext, RecentItemsManager recentItemsManager) + public CommitManagerProvider(IThreadingContext threadingContext, RecentItemsManager recentItemsManager, IGlobalOptionService globalOptions) { _threadingContext = threadingContext; _recentItemsManager = recentItemsManager; + _globalOptions = globalOptions; } IAsyncCompletionCommitManager? IAsyncCompletionCommitManagerProvider.GetOrCreate(ITextView textView) @@ -36,7 +39,7 @@ public CommitManagerProvider(IThreadingContext threadingContext, RecentItemsMana return null; } - return new CommitManager(textView, _recentItemsManager, _threadingContext); + return new CommitManager(textView, _recentItemsManager, _globalOptions, _threadingContext); } } } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CompletionSource.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CompletionSource.cs index dc66591536a76..7aaeee93c280d 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CompletionSource.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CompletionSource.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; @@ -29,6 +30,7 @@ using Microsoft.VisualStudio.Text.Editor; using AsyncCompletionData = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; using RoslynCompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem; +using VSCompletionContext = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionContext; using VSCompletionItem = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem; using VSUtilities = Microsoft.VisualStudio.Utilities; @@ -46,13 +48,13 @@ internal sealed class CompletionSource : ForegroundThreadAffinitizedObject, IAsy internal const string PotentialCommitCharacters = nameof(PotentialCommitCharacters); internal const string ExcludedCommitCharacters = nameof(ExcludedCommitCharacters); internal const string NonBlockingCompletion = nameof(NonBlockingCompletion); - internal const string TypeImportCompletionEnabled = nameof(TypeImportCompletionEnabled); internal const string TargetTypeFilterExperimentEnabled = nameof(TargetTypeFilterExperimentEnabled); + internal const string ExpandedItemsTask = nameof(ExpandedItemsTask); - private static readonly ImmutableArray s_WarningImageAttributeImagesArray = + private static readonly ImmutableArray s_warningImageAttributeImagesArray = ImmutableArray.Create(new ImageElement(Glyph.CompletionWarning.GetImageId(), EditorFeaturesResources.Warning_image_element)); - private static readonly EditorOptionKey NonBlockingCompletionEditorOption = new(NonBlockingCompletion); + private static readonly EditorOptionKey s_nonBlockingCompletionEditorOption = new(NonBlockingCompletion); // Use CWT to cache data needed to create VSCompletionItem, so the table would be cleared when Roslyn completion item cache is cleared. private static readonly ConditionalWeakTable> s_roslynItemToVsItemData = @@ -66,6 +68,7 @@ internal sealed class CompletionSource : ForegroundThreadAffinitizedObject, IAsy private readonly IAsynchronousOperationListener _asyncListener; private readonly IGlobalOptionService _globalOptions; private bool _snippetCompletionTriggeredIndirectly; + private bool _responsiveCompletionEnabled; internal CompletionSource( ITextView textView, @@ -112,13 +115,14 @@ public AsyncCompletionData.CompletionStartData InitializeCompletion( return AsyncCompletionData.CompletionStartData.DoesNotParticipateInCompletion; } - var options = CompletionOptions.From(document.Project); + var options = _globalOptions.GetCompletionOptions(document.Project.Language); // The Editor supports the option per textView. // There could be mixed desired behavior per textView and even per same completion session. // The right fix would be to send this information as a result of the method. // Then, the Editor would choose the right behavior for mixed cases. - _textView.Options.GlobalOptions.SetOptionValue(NonBlockingCompletionEditorOption, !_globalOptions.GetOption(CompletionViewOptions.BlockForCompletionItems, service.Language)); + _textView.Options.GlobalOptions.SetOptionValue(s_nonBlockingCompletionEditorOption, !_globalOptions.GetOption(CompletionViewOptions.BlockForCompletionItems, service.Language)); + _responsiveCompletionEnabled = _textView.Options.GetOptionValue(DefaultOptions.ResponsiveCompletionOptionId); // In case of calls with multiple completion services for the same view (e.g. TypeScript and C#), those completion services must not be called simultaneously for the same session. // Therefore, in each completion session we use a list of commit character for a specific completion service and a specific content type. @@ -128,7 +132,8 @@ public AsyncCompletionData.CompletionStartData InitializeCompletion( // Set it later if met the condition. _snippetCompletionTriggeredIndirectly = false; - CheckForExperimentStatus(_textView, options); + // For telemetry reporting purpose + _textView.Properties[TargetTypeFilterExperimentEnabled] = options.TargetTypedCompletionFilter; var sourceText = document.GetTextSynchronously(cancellationToken); @@ -139,17 +144,6 @@ public AsyncCompletionData.CompletionStartData InitializeCompletion( triggerLocation.Snapshot, service.GetDefaultCompletionListSpan(sourceText, triggerLocation.Position).ToSpan())) : AsyncCompletionData.CompletionStartData.DoesNotParticipateInCompletion; - - // For telemetry reporting purpose - static void CheckForExperimentStatus(ITextView textView, in CompletionOptions options) - { - textView.Properties[TargetTypeFilterExperimentEnabled] = options.TargetTypedCompletionFilter; - - var importCompletionOptionValue = options.ShowItemsFromUnimportedNamespaces; - var importCompletionExperimentValue = options.TypeImportCompletion; - var isTypeImportEnababled = importCompletionOptionValue == true || (importCompletionOptionValue == null && importCompletionExperimentValue); - textView.Properties[TypeImportCompletionEnabled] = isTypeImportEnababled; - } } private bool ShouldTriggerCompletion( @@ -184,7 +178,7 @@ private bool ShouldTriggerCompletion( var roslynTrigger = Helpers.GetRoslynTrigger(trigger, triggerLocation); // The completion service decides that user may want a completion. - if (completionService.ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, sourceText, triggerLocation.Position, roslynTrigger, options)) + if (completionService.ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, sourceText, triggerLocation.Position, roslynTrigger, options, document.Project.Solution.Options)) { return true; } @@ -222,7 +216,7 @@ private bool TryInvokeSnippetCompletion( return true; } - public Task GetCompletionContextAsync( + public async Task GetCompletionContextAsync( IAsyncCompletionSession session, AsyncCompletionData.CompletionTrigger trigger, SnapshotPoint triggerLocation, @@ -232,10 +226,135 @@ private bool TryInvokeSnippetCompletion( if (session is null) throw new ArgumentNullException(nameof(session)); - return GetCompletionContextWorkerAsync(session, trigger, triggerLocation, isExpanded: false, cancellationToken); + var document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + return VSCompletionContext.Empty; + + // The computation of completion items is divided into two tasks: + // + // 1. "Core" items (i.e. non-expanded) which should be included in the list regardless of the selection of expander. + // Right now this includes all items except those from unimported namespaces. + // + // 2. Expanded items which only show in the completion list when expander is selected, or by default if the corresponding + // features are enabled. Right now only items from unimported namespaces are associated with expander. + // + // #1 is the essence of completion so we'd always wait until its task is completed and return the results. However, because we have + // a really tight perf budget in completion, and computing those items in #2 could be expensive especially in a large solution + // (e.g. requires syntax/symbol indices and/or runs in OOP,) we decide to kick off the computation in parallel when completion is + // triggered, but only include its results if it's completed by the time task #1 is completed, otherwise we don't wait on it and + // just return items from #1 immediately. Task #2 will still be running in the background (until session is dismissed/committed,) + // and we'd check back to see if it's completed whenever we have a chance to update the completion list, i.e. when user typed another + // character, a filter was selected, etc. If so, those items will be added as part of the refresh. + // + // The reason of adopting this approach is we want to minimize typing delays. There are two ways user might perceive a delay in typing. + // First, they could see a delay between typing a character and completion list being displayed if they want to examine the items available. + // Second, they might be typing continuously w/o paying attention to completion list, and simply expect the completion to do the "right thing" + // when a commit char is typed (e.g. commit "cancellationToken" when typing 'can$TAB$'). However, the commit could be delayed if completion is + // still waiting on the computation of all available items, which manifests as UI delays and in worst case timeouts in commit which results in + // unexpected behavior (e.g. typing 'can$TAB$' results in a 250ms UI freeze and still ends up with "can" instead of "cancellationToken".) + // + // This approach would ensure the computation of #2 will not be the cause of such delays, with the obvious trade off of potentially not providing + // expanded items until later (or never) in a completion session even if the feature is enabled. Note that in most cases we'd expect task #2 to finish + // in time and complete result would be available from the start of the session. However, even in the case only partial result is returned at the start, + // we still believe this is acceptable given how critical perf is in typing scenario. + // Additionally, expanded items are usually considered complementary. The need for them only rise occasionally (it's rare when users need to add imports,) + // and when they are needed, our hypothesis is because of their more intrusive nature (adding an import to the document) users would more likely to + // contemplate such action thus typing slower before commit and/or spending more time examining the list, which give us some opportunities + // to still provide those items later before they are truly required. + + var options = _globalOptions.GetCompletionOptions(document.Project.Language); + + if (!options.ShouldShowItemsFromUnimportNamspaces()) + { + // No need to trigger expanded providers at all if the feature is disabled, just trigger core providers and return; + var (context, list) = await GetCompletionContextWorkerAsync(document, trigger, triggerLocation, + options with { ExpandedCompletionBehavior = ExpandedCompletionMode.NonExpandedItemsOnly }, cancellationToken).ConfigureAwait(false); + + AddPropertiesToSession(session, list, triggerLocation); + return context; + } + else if (!_responsiveCompletionEnabled) + { + // We tie the behavior of delaying expand items to editor's "responsive completion" option. + // i.e. "responsive completion" disabled == always wait for all items to be calculated. + var (context, list) = await GetCompletionContextWorkerAsync(document, trigger, triggerLocation, + options with { ExpandedCompletionBehavior = ExpandedCompletionMode.AllItems }, cancellationToken).ConfigureAwait(false); + + AddPropertiesToSession(session, list, triggerLocation); + AsyncCompletionLogger.LogImportCompletionGetContext(isBlocking: true, delayed: false); + return context; + } + else + { + // 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 expandedItemsTask = Task.Run(async () => + { + var result = await GetCompletionContextWorkerAsync(document, trigger, triggerLocation, + options with { ExpandedCompletionBehavior = ExpandedCompletionMode.ExpandedItemsOnly }, cancellationToken).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 + // majority of the sessions, then we might consider doing that instead of return immediately. + // 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); + + return result; + }, cancellationToken); + + // Now trigger and wait for core providers to return; + var (nonExpandedContext, nonExpandedCompletionList) = await GetCompletionContextWorkerAsync(document, trigger, triggerLocation, + options with { ExpandedCompletionBehavior = ExpandedCompletionMode.NonExpandedItemsOnly }, cancellationToken).ConfigureAwait(false); + AddPropertiesToSession(session, nonExpandedCompletionList, triggerLocation); + + if (expandedItemsTask.IsCompleted) + { + // the task of expanded item is completed, get the result and combine it with result of non-expanded items. + var (expandedContext, expandedCompletionList) = await expandedItemsTask.ConfigureAwait(false); + AddPropertiesToSession(session, expandedCompletionList, triggerLocation); + AsyncCompletionLogger.LogImportCompletionGetContext(isBlocking: false, delayed: false); + + return CombineCompletionContext(nonExpandedContext, expandedContext); + } + else + { + // Expanded item task still running. Save it to the session and return non-expanded items immediately. + // Also start the stopwatch since we'd like to know how long it takes for the expand task to finish + // after core providers completed (instead of how long it takes end-to-end). + stopwatch.Start(); + + session.Properties[ExpandedItemsTask] = expandedItemsTask; + AsyncCompletionLogger.LogImportCompletionGetContext(isBlocking: false, delayed: true); + + return nonExpandedContext; + } + } + + static VSCompletionContext CombineCompletionContext(VSCompletionContext context1, VSCompletionContext context2) + { + if (context1.Items.IsEmpty && context1.SuggestionItemOptions is null) + return context2; + + if (context2.Items.IsEmpty && context2.SuggestionItemOptions is null) + return context1; + + using var _ = ArrayBuilder.GetInstance(context1.Items.Length + context2.Items.Length, out var itemsBuilder); + itemsBuilder.AddRange(context1.Items); + itemsBuilder.AddRange(context2.Items); + + var filterStates = FilterSet.CombineFilterStates(context1.Filters, context2.Filters); + + var suggestionItem = context1.SuggestionItemOptions ?? context2.SuggestionItemOptions; + var hint = suggestionItem == null ? AsyncCompletionData.InitialSelectionHint.RegularSelection : AsyncCompletionData.InitialSelectionHint.SoftSelection; + + return new VSCompletionContext(itemsBuilder.ToImmutableAndClear(), suggestionItem, hint, filterStates); + } } - public async Task GetExpandedCompletionContextAsync( + public async Task GetExpandedCompletionContextAsync( IAsyncCompletionSession session, AsyncCompletionData.CompletionExpander expander, AsyncCompletionData.CompletionTrigger intialTrigger, @@ -246,38 +365,49 @@ private bool TryInvokeSnippetCompletion( if (expander == FilterSet.Expander && session.Properties.TryGetProperty(ExpandedItemTriggerLocation, out SnapshotPoint initialTriggerLocation)) { AsyncCompletionLogger.LogExpanderUsage(); - return await GetCompletionContextWorkerAsync(session, intialTrigger, initialTriggerLocation, isExpanded: true, cancellationToken).ConfigureAwait(false); + + // It's possible we didn't provide expanded items at the beginning of completion session because it was slow even if the feature is enabled. + // ExpandedItemsTask would be available in this case, so we just need to return its result. + if (session.Properties.TryGetProperty(ExpandedItemsTask, out Task<(VSCompletionContext, CompletionList)> expandedItemsTask)) + { + // Make sure the task is removed when returning expanded items, + // so duplicated items won't be added in subsequent list updates. + session.Properties.RemoveProperty(ExpandedItemsTask); + var (expandedContext, expandedCompletionList) = await expandedItemsTask.ConfigureAwait(false); + AddPropertiesToSession(session, expandedCompletionList, initialTriggerLocation); + return expandedContext; + } + + // We only reach here when expanded items are disabled, but user requested them explicitly via expander. + // In this case, enable expanded items and trigger the completion only for them. + var document = initialTriggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document != null) + { + // User selected expander explicitly, which means we need to collect and return + // items from unimported namespace (and only those items) regardless of whether it's enabled. + var options = _globalOptions.GetCompletionOptions(document.Project.Language) with + { + ShowItemsFromUnimportedNamespaces = true, + ExpandedCompletionBehavior = ExpandedCompletionMode.ExpandedItemsOnly + }; + + var (context, completionList) = await GetCompletionContextWorkerAsync(document, intialTrigger, initialTriggerLocation, options, cancellationToken).ConfigureAwait(false); + AddPropertiesToSession(session, completionList, initialTriggerLocation); + + return context; + } } - return AsyncCompletionData.CompletionContext.Empty; + return VSCompletionContext.Empty; } - private async Task GetCompletionContextWorkerAsync( - IAsyncCompletionSession session, + private async Task<(VSCompletionContext, CompletionList)> GetCompletionContextWorkerAsync( + Document document, AsyncCompletionData.CompletionTrigger trigger, SnapshotPoint triggerLocation, - bool isExpanded, + CompletionOptions options, CancellationToken cancellationToken) { - var document = triggerLocation.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document == null) - { - return AsyncCompletionData.CompletionContext.Empty; - } - - var completionService = document.GetRequiredLanguageService(); - - var roslynTrigger = Helpers.GetRoslynTrigger(trigger, triggerLocation); - if (_snippetCompletionTriggeredIndirectly) - { - roslynTrigger = new CompletionTrigger(CompletionTriggerKind.Snippets); - } - - var options = CompletionOptions.From(document.Project) with - { - IsExpandedCompletion = isExpanded - }; - if (_isDebuggerTextView) { options = options with @@ -287,66 +417,61 @@ private bool TryInvokeSnippetCompletion( }; } - var (completionList, expandItemsAvailable) = await completionService.GetCompletionsInternalAsync( - document, - triggerLocation, - options, - roslynTrigger, - _roles, - cancellationToken).ConfigureAwait(false); + var completionService = document.GetRequiredLanguageService(); + var roslynTrigger = _snippetCompletionTriggeredIndirectly + ? new CompletionTrigger(CompletionTriggerKind.Snippets) + : Helpers.GetRoslynTrigger(trigger, triggerLocation); + + var completionList = await completionService.GetCompletionsAsync( + document, triggerLocation, options, document.Project.Solution.Options, roslynTrigger, _roles, cancellationToken).ConfigureAwait(false); - ImmutableArray items; - AsyncCompletionData.SuggestionItemOptions? suggestionItemOptions; var filterSet = new FilterSet(); + using var _ = ArrayBuilder.GetInstance(completionList.Items.Length, out var itemsBuilder); - if (completionList == null) + foreach (var roslynItem in completionList.Items) { - items = ImmutableArray.Empty; - suggestionItemOptions = null; + cancellationToken.ThrowIfCancellationRequested(); + var item = Convert(document, roslynItem, filterSet, triggerLocation); + itemsBuilder.Add(item); } - else + + var filters = filterSet.GetFilterStatesInSet(); + var items = itemsBuilder.ToImmutable(); + + if (completionList.SuggestionModeItem is null) + return (new(items, suggestionItemOptions: null, selectionHint: AsyncCompletionData.InitialSelectionHint.RegularSelection, filters), completionList); + + var suggestionItemOptions = new AsyncCompletionData.SuggestionItemOptions( + completionList.SuggestionModeItem.DisplayText, + completionList.SuggestionModeItem.Properties.TryGetValue(Description, out var description) ? description : string.Empty); + + return (new(items, suggestionItemOptions, selectionHint: AsyncCompletionData.InitialSelectionHint.SoftSelection, filters), completionList); + } + + private static void AddPropertiesToSession(IAsyncCompletionSession session, CompletionList completionList, SnapshotPoint triggerLocation) + { + // 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. + session.Properties[CompletionListSpan] = completionList.Span; + + // This is a code supporting original completion scenarios: + // Controller.Session_ComputeModel: if completionList.SuggestionModeItem != null, then suggestionMode = true + // If there are suggestionItemOptions, then later HandleNormalFiltering should set selection to SoftSelection. + if (!session.Properties.TryGetProperty(HasSuggestionItemOptions, out bool hasSuggestionItemOptionsBefore) || !hasSuggestionItemOptionsBefore) { - var itemsBuilder = new ArrayBuilder(completionList.Items.Length); - foreach (var roslynItem in completionList.Items) - { - cancellationToken.ThrowIfCancellationRequested(); - var item = Convert(document, roslynItem, filterSet, triggerLocation); - itemsBuilder.Add(item); - } + session.Properties[HasSuggestionItemOptions] = completionList.SuggestionModeItem != null; + } - items = itemsBuilder.ToImmutableAndFree(); - - suggestionItemOptions = completionList.SuggestionModeItem != null - ? new AsyncCompletionData.SuggestionItemOptions( - completionList.SuggestionModeItem.DisplayText, - completionList.SuggestionModeItem.Properties.TryGetValue(Description, out var description) - ? description - : string.Empty) - : null; - - // 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. - session.Properties[CompletionListSpan] = completionList.Span; - - // This is a code supporting original completion scenarios: - // Controller.Session_ComputeModel: if completionList.SuggestionModeItem != null, then suggestionMode = true - // If there are suggestionItemOptions, then later HandleNormalFiltering should set selection to SoftSelection. - if (!session.Properties.TryGetProperty(HasSuggestionItemOptions, out bool hasSuggestionItemOptionsBefore) || !hasSuggestionItemOptionsBefore) + var excludedCommitCharacters = GetExcludedCommitCharacters(completionList.Items); + if (excludedCommitCharacters.Length > 0) + { + if (session.Properties.TryGetProperty(ExcludedCommitCharacters, out ImmutableArray excludedCommitCharactersBefore)) { - session.Properties[HasSuggestionItemOptions] = suggestionItemOptions != null; + excludedCommitCharacters = excludedCommitCharacters.Union(excludedCommitCharactersBefore).ToImmutableArray(); } - var excludedCommitCharacters = GetExcludedCommitCharacters(completionList.Items); - if (excludedCommitCharacters.Length > 0) - { - if (session.Properties.TryGetProperty(ExcludedCommitCharacters, out ImmutableArray excludedCommitCharactersBefore)) - { - excludedCommitCharacters = excludedCommitCharacters.Union(excludedCommitCharactersBefore).ToImmutableArray(); - } - - session.Properties[ExcludedCommitCharacters] = excludedCommitCharacters; - } + session.Properties[ExcludedCommitCharacters] = excludedCommitCharacters; } // We need to remember the trigger location for when a completion service claims expanded items are available @@ -354,19 +479,10 @@ private bool TryInvokeSnippetCompletion( // so when they are requested via expander later, we can retrieve it. // Technically we should save the trigger location for each individual service that made such claim, but in reality only Roslyn's // completion service uses expander, so we can get away with not making such distinction. - if (!isExpanded && expandItemsAvailable) + if (!session.Properties.ContainsProperty(ExpandedItemTriggerLocation)) { session.Properties[ExpandedItemTriggerLocation] = triggerLocation; } - - // It's possible that some providers can provide expanded items, in which case we will need to show expander as unselected. - return new AsyncCompletionData.CompletionContext( - items, - suggestionItemOptions, - suggestionItemOptions == null - ? AsyncCompletionData.InitialSelectionHint.RegularSelection - : AsyncCompletionData.InitialSelectionHint.SoftSelection, - filterSet.GetFilterStatesInSet(addUnselectedExpander: expandItemsAvailable)); } public async Task GetDescriptionAsync(IAsyncCompletionSession session, VSCompletionItem item, CancellationToken cancellationToken) @@ -390,7 +506,7 @@ private bool TryInvokeSnippetCompletion( if (service == null) return null; - var options = CompletionOptions.From(document.Project); + var options = _globalOptions.GetCompletionOptions(document.Project.Language); var displayOptions = SymbolDescriptionOptions.From(document.Project); var description = await service.GetDescriptionAsync(document, roslynItem, options, displayOptions, cancellationToken).ConfigureAwait(false); if (description == null) @@ -414,36 +530,15 @@ private bool TryInvokeSnippetCompletion( /// to transient objects, which would cause memory leak (among other potential issues) if cached. /// So as a compromise, we cache data that can be calculated from Roslyn completion item to avoid repeated /// calculation cost for cached Roslyn completion items. + /// FilterSetData is the bit vector value from the FilterSet of this item. /// - private readonly struct VSCompletionItemData - { - public VSCompletionItemData( - string displayText, ImageElement icon, ImmutableArray filters, - int filterSetData, ImmutableArray attributeIcons, string insertionText) - { - DisplayText = displayText; - Icon = icon; - Filters = filters; - FilterSetData = filterSetData; - AttributeIcons = attributeIcons; - InsertionText = insertionText; - } - - public string DisplayText { get; } - - public ImageElement Icon { get; } - - public ImmutableArray Filters { get; } - - /// - /// This is the bit vector value from the FilterSet of this item. - /// - public int FilterSetData { get; } - - public ImmutableArray AttributeIcons { get; } - - public string InsertionText { get; } - } + private readonly record struct VSCompletionItemData( + string DisplayText, + ImageElement Icon, + ImmutableArray Filters, + int FilterSetData, + ImmutableArray AttributeIcons, + string InsertionText); private VSCompletionItem Convert( Document document, @@ -472,15 +567,15 @@ private VSCompletionItem Convert( } var supportedPlatforms = SymbolCompletionItem.GetSupportedPlatforms(roslynItem, document.Project.Solution); - var attributeImages = supportedPlatforms != null ? s_WarningImageAttributeImagesArray : ImmutableArray.Empty; + var attributeImages = supportedPlatforms != null ? s_warningImageAttributeImagesArray : ImmutableArray.Empty; itemData = new VSCompletionItemData( - displayText: roslynItem.GetEntireDisplayText(), - icon: new ImageElement(new ImageId(imageId.Guid, imageId.Id), roslynItem.DisplayText), - filters: filters, - filterSetData: filterSetData, - attributeIcons: attributeImages, - insertionText: insertionText); + DisplayText: roslynItem.GetEntireDisplayText(), + Icon: new ImageElement(new ImageId(imageId.Guid, imageId.Id), roslynItem.DisplayText), + Filters: filters, + FilterSetData: filterSetData, + AttributeIcons: attributeImages, + InsertionText: insertionText); // It doesn't make sense to cache VS item data for those Roslyn items created from scratch for each session, // since CWT uses object identity for comparison. diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterSet.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterSet.cs index d38bd121399fb..e01228ddbbd48 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterSet.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterSet.cs @@ -170,19 +170,12 @@ internal static List GetFilters(RoslynCompletionItem item) public void CombineData(int filterSetData) => _vector[filterSetData] = true; - public ImmutableArray GetFilterStatesInSet(bool addUnselectedExpander) + public ImmutableArray GetFilterStatesInSet() { - var builder = new ArrayBuilder(); + using var _ = ArrayBuilder.GetInstance(out var builder); - // An unselected expander is only added if `addUnselectedExpander == true` and the expander is not in the set. - if (_vector[s_expanderMask]) - { - builder.Add(new CompletionFilterWithState(Expander, isAvailable: true, isSelected: true)); - } - else if (addUnselectedExpander) - { - builder.Add(new CompletionFilterWithState(Expander, isAvailable: true, isSelected: false)); - } + // We always show expander but its selection state depends on whether it is in the set. + builder.Add(new CompletionFilterWithState(Expander, isAvailable: true, isSelected: _vector[s_expanderMask])); foreach (var filterWithMask in s_filters) { @@ -192,19 +185,45 @@ public ImmutableArray GetFilterStatesInSet(bool addUn } } - return builder.ToImmutableAndFree(); + return builder.ToImmutable(); } - private readonly struct FilterWithMask + /// + /// Combine two filter lists while preserving the order as defined in . + /// + public static ImmutableArray CombineFilterStates(ImmutableArray filters1, ImmutableArray filters2) { - public readonly CompletionFilter Filter; - public readonly int Mask; + using var _1 = PooledDictionary.GetInstance(out var filterStateMap); + AddFilterState(filters1); + AddFilterState(filters2); - public FilterWithMask(CompletionFilter filter, int mask) + using var _2 = ArrayBuilder.GetInstance(out var builder); + if (filterStateMap.TryGetValue(Expander, out var isSelected)) { - Filter = filter; - Mask = mask; + builder.Add(new CompletionFilterWithState(Expander, isAvailable: true, isSelected: isSelected)); + } + + // Make sure filters are kept in the relative order of their declaration above. + foreach (var filterWithMask in s_filters) + { + if (filterStateMap.TryGetValue(filterWithMask.Filter, out isSelected)) + { + builder.Add(new CompletionFilterWithState(filterWithMask.Filter, isAvailable: true, isSelected: isSelected)); + } + } + + return builder.ToImmutable(); + + void AddFilterState(ImmutableArray filterStates) + { + foreach (var state in filterStates) + { + filterStateMap.TryGetValue(state.Filter, out var isSelected); + filterStateMap[state.Filter] = state.IsSelected || isSelected; + } } } + + private readonly record struct FilterWithMask(CompletionFilter Filter, int Mask); } } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/Helpers.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/Helpers.cs index 2f6adf686cdfe..a811fbb8d2376 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/Helpers.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/Helpers.cs @@ -3,8 +3,11 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Text; +using Roslyn.Utilities; using EditorAsyncCompletionData = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; using RoslynCompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem; using RoslynTrigger = Microsoft.CodeAnalysis.Completion.CompletionTrigger; @@ -24,7 +27,7 @@ internal static class Helpers /// We retrieve this character from triggerLocation. /// /// Roslyn completion trigger - internal static RoslynTrigger GetRoslynTrigger(EditorAsyncCompletionData.CompletionTrigger trigger, SnapshotPoint triggerLocation) + public static RoslynTrigger GetRoslynTrigger(EditorAsyncCompletionData.CompletionTrigger trigger, SnapshotPoint triggerLocation) { var completionTriggerKind = GetRoslynTriggerKind(trigger.Reason); if (completionTriggerKind == CompletionTriggerKind.Deletion) @@ -49,7 +52,7 @@ internal static RoslynTrigger GetRoslynTrigger(EditorAsyncCompletionData.Complet } } - internal static CompletionTriggerKind GetRoslynTriggerKind(EditorAsyncCompletionData.CompletionTriggerReason triggerReason) + public static CompletionTriggerKind GetRoslynTriggerKind(EditorAsyncCompletionData.CompletionTriggerReason triggerReason) { return triggerReason switch { @@ -61,7 +64,7 @@ internal static CompletionTriggerKind GetRoslynTriggerKind(EditorAsyncCompletion }; } - internal static CompletionFilterReason GetFilterReason(EditorAsyncCompletionData.CompletionTriggerReason triggerReason) + public static CompletionFilterReason GetFilterReason(EditorAsyncCompletionData.CompletionTriggerReason triggerReason) { return triggerReason switch { @@ -71,7 +74,7 @@ internal static CompletionFilterReason GetFilterReason(EditorAsyncCompletionData }; } - internal static bool IsFilterCharacter(RoslynCompletionItem item, char ch, string textTypedSoFar) + public static bool IsFilterCharacter(RoslynCompletionItem item, char ch, string textTypedSoFar) { // Exclude standard commit character upfront because TextTypedSoFarMatchesItem can miss them on non-Windows platforms. if (IsStandardCommitCharacter(ch)) @@ -114,7 +117,7 @@ internal static bool IsFilterCharacter(RoslynCompletionItem item, char ch, strin return false; } - internal static bool TextTypedSoFarMatchesItem(RoslynCompletionItem item, string textTypedSoFar) + public static bool TextTypedSoFarMatchesItem(RoslynCompletionItem item, string textTypedSoFar) { if (textTypedSoFar.Length > 0) { @@ -127,12 +130,12 @@ internal static bool TextTypedSoFarMatchesItem(RoslynCompletionItem item, string } // Tab, Enter and Null (call invoke commit) are always commit characters. - internal static bool IsStandardCommitCharacter(char c) + public static bool IsStandardCommitCharacter(char c) => c is '\t' or '\n' or '\0'; // This is a temporarily method to support preference of IntelliCode items comparing to non-IntelliCode items. // We expect that Editor will introduce this support and we will get rid of relying on the "★" then. - internal static bool IsPreferredItem(this VSCompletionItem completionItem) + public static bool IsPreferredItem(this VSCompletionItem completionItem) => completionItem.DisplayText.StartsWith("★"); } } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs index 2a22df8398a2e..030692e4ad810 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.CompletionListUpdater.cs @@ -89,7 +89,7 @@ public CompletionListUpdater( if (_document != null) { _completionService = _document.GetLanguageService(); - _completionRules = _completionService?.GetRules(CompletionOptions.From(_document.Project)) ?? CompletionRules.Default; + _completionRules = _completionService?.GetRules(globalOptions.GetCompletionOptions(_document.Project.Language)) ?? CompletionRules.Default; // Let us make the completion Helper used for non-Roslyn items case-sensitive. // We can change this if get requests from partner teams. @@ -407,7 +407,8 @@ private void AddCompletionItems(List> list, Cancel private ImmutableArray GetHighlightedList(IReadOnlyList> items, CancellationToken cancellationToken) { - return items.SelectAsArray(matchResult => + using var _ = ArrayBuilder.GetInstance(items.Count, out var builder); + builder.AddRange(items.Select(matchResult => { cancellationToken.ThrowIfCancellationRequested(); var highlightedSpans = _highlightMatchingPortions @@ -415,7 +416,9 @@ private ImmutableArray GetHighlightedList(IReadOnly : ImmutableArray.Empty; return new CompletionItemWithHighlight(matchResult.EditorCompletionItem, highlightedSpans); - }); + })); + + return builder.ToImmutable(); static ImmutableArray GetHighlightedSpans( MatchResult matchResult, diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs index dba67a817d561..0bc14462de196 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs @@ -7,10 +7,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; using Roslyn.Utilities; using RoslynCompletionItem = Microsoft.CodeAnalysis.Completion.CompletionItem; +using RoslynCompletionList = Microsoft.CodeAnalysis.Completion.CompletionList; using VSCompletionItem = Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data.CompletionItem; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion @@ -18,6 +20,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncComplet internal sealed partial class ItemManager : IAsyncCompletionItemManager { public const string AggressiveDefaultsMatchingOptionName = "AggressiveDefaultsMatchingOption"; + private const string CombinedSortedList = nameof(CombinedSortedList); private readonly RecentItemsManager _recentItemsManager; private readonly IGlobalOptionService _globalOptions; @@ -41,21 +44,61 @@ public Task> SortCompletionListAsync( AsyncCompletionLogger.LogSessionContainsTargetTypeFilter(); } - if (session.TextView.Properties.TryGetProperty(CompletionSource.TypeImportCompletionEnabled, out bool isTypeImportCompletionEnabled) && isTypeImportCompletionEnabled) - AsyncCompletionLogger.LogSessionWithTypeImportCompletionEnabled(); - // Sort by default comparer of Roslyn CompletionItem var sortedItems = data.InitialList.OrderBy(GetOrAddRoslynCompletionItem).ToImmutableArray(); return Task.FromResult(sortedItems); } - public Task UpdateCompletionListAsync( + public async Task UpdateCompletionListAsync( IAsyncCompletionSession session, AsyncCompletionSessionDataSnapshot data, CancellationToken cancellationToken) { + // As explained in more details in the comments for `CompletionSource.GetCompletionContextAsync`, expanded items might + // not be provided upon initial trigger of completion to reduce typing delays, even if they are supposed to be included by default. + // While we do not expect to run in to this scenario very often, we'd still want to minimize the impact on user experience of this feature + // as best as we could when it does occur. So the solution we came up with is this: if we decided to not include expanded items (because the + // computation is running too long,) we will let it run in the background as long as the completion session is still active. Then whenever + // any user input that would cause the completion list to refresh, we will check the state of this background task and add expanded items as part + // of the update if they are available. + // There is a `CompletionContext.IsIncomplete` flag, which is only supported in LSP mode at the moment. Therefore we opt to handle the checking + // and combining the items in Roslyn until the `IsIncomplete` flag is fully supported in classic mode. + + if (session.Properties.TryGetProperty(CombinedSortedList, out ImmutableArray combinedSortedList)) + { + // Always use the previously saved combined list if available. + data = new AsyncCompletionSessionDataSnapshot(combinedSortedList, data.Snapshot, data.Trigger, data.InitialTrigger, data.SelectedFilters, + data.IsSoftSelected, data.DisplaySuggestionItem, data.Defaults); + } + else if (session.Properties.TryGetProperty(CompletionSource.ExpandedItemsTask, out Task<(CompletionContext, RoslynCompletionList)> task) + && task.Status == TaskStatus.RanToCompletion) + { + // Make sure the task is removed when Adding expanded items, + // so duplicated items won't be added in subsequent list updates. + session.Properties.RemoveProperty(CompletionSource.ExpandedItemsTask); + + var (expandedContext, _) = await task.ConfigureAwait(false); + if (expandedContext.Items.Length > 0) + { + // Here we rely on the implementation detail of `CompletionItem.CompareTo`, which always put expand items after regular ones. + var itemsBuilder = ImmutableArray.CreateBuilder(expandedContext.Items.Length + data.InitialSortedList.Length); + itemsBuilder.AddRange(data.InitialSortedList); + itemsBuilder.AddRange(expandedContext.Items); + var combinedList = itemsBuilder.MoveToImmutable(); + + // Add expanded items into a combined list, and save it to be used for future updates during the same session. + session.Properties[CombinedSortedList] = combinedList; + var combinedFilterStates = FilterSet.CombineFilterStates(expandedContext.Filters, data.SelectedFilters); + + data = new AsyncCompletionSessionDataSnapshot(combinedList, data.Snapshot, data.Trigger, data.InitialTrigger, combinedFilterStates, + data.IsSoftSelected, data.DisplaySuggestionItem, data.Defaults); + } + + AsyncCompletionLogger.LogSessionWithDelayedImportCompletionIncludedInUpdate(); + } + var updater = new CompletionListUpdater(session, data, _recentItemsManager, _globalOptions); - return Task.FromResult(updater.UpdateCompletionList(cancellationToken)); + return updater.UpdateCompletionList(cancellationToken); } private static RoslynCompletionItem GetOrAddRoslynCompletionItem(VSCompletionItem vsItem) diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs index 8d976778353b6..6988656fe0bbc 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; @@ -69,7 +70,8 @@ public async Task GetQuickInfoItemAsync(IAsyncQuickIn { cancellationToken.ThrowIfCancellationRequested(); - var item = await service.GetQuickInfoAsync(document, triggerPoint.Value, cancellationToken).ConfigureAwait(false); + var options = SymbolDescriptionOptions.From(document.Project); + var item = await service.GetQuickInfoAsync(document, triggerPoint.Value, options, cancellationToken).ConfigureAwait(false); if (item != null) { var textVersion = snapshot.Version; diff --git a/src/EditorFeatures/Core/Implementation/KeywordHighlighting/HighlighterViewTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/KeywordHighlighting/HighlighterViewTaggerProvider.cs index 2401f0b76d42d..d82d80555ae11 100644 --- a/src/EditorFeatures/Core/Implementation/KeywordHighlighting/HighlighterViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/KeywordHighlighting/HighlighterViewTaggerProvider.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/AbstractInProcLanguageClient.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/AbstractInProcLanguageClient.cs index 17f8632bc6f0a..07451e43cb3e0 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/AbstractInProcLanguageClient.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/AbstractInProcLanguageClient.cs @@ -28,10 +28,6 @@ internal abstract partial class AbstractInProcLanguageClient : ILanguageClient, private readonly IThreadingContext _threadingContext; private readonly ILspLoggerFactory _lspLoggerFactory; - /// - /// Legacy support for LSP push diagnostics. - /// - private readonly IDiagnosticService? _diagnosticService; private readonly IAsynchronousOperationListenerProvider _listenerProvider; private readonly AbstractRequestDispatcherFactory _requestDispatcherFactory; private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; @@ -46,7 +42,12 @@ internal abstract partial class AbstractInProcLanguageClient : ILanguageClient, /// /// Gets the name of the language client (displayed to the user). /// - public abstract string Name { get; } + public string Name => ServerKind.ToUserVisibleString(); + + /// + /// An enum representing this server instance. + /// + public abstract WellKnownLspServerKinds ServerKind { get; } /// /// The set of languages that this LSP server supports and can return results for. @@ -82,7 +83,6 @@ public event AsyncEventHandler? StopAsync { add { } remove { } } public AbstractInProcLanguageClient( AbstractRequestDispatcherFactory requestDispatcherFactory, IGlobalOptionService globalOptions, - IDiagnosticService? diagnosticService, IAsynchronousOperationListenerProvider listenerProvider, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, ILspLoggerFactory lspLoggerFactory, @@ -91,7 +91,6 @@ public AbstractInProcLanguageClient( { _requestDispatcherFactory = requestDispatcherFactory; GlobalOptions = globalOptions; - _diagnosticService = diagnosticService; _listenerProvider = listenerProvider; _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; _diagnosticsClientName = diagnosticsClientName; @@ -207,11 +206,9 @@ public ILanguageServerTarget Create( GlobalOptions, _listenerProvider, logger, - _diagnosticService, SupportedLanguages, clientName: _diagnosticsClientName, - userVisibleServerName: this.Name, - telemetryServerTypeName: this.GetType().Name); + ServerKind); } public abstract ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities); diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/AlwaysActivateInProcLanguageClient.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/AlwaysActivateInProcLanguageClient.cs index 657502f8e140d..fa0b7b12692b4 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/AlwaysActivateInProcLanguageClient.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/AlwaysActivateInProcLanguageClient.cs @@ -43,15 +43,13 @@ public AlwaysActivateInProcLanguageClient( DefaultCapabilitiesProvider defaultCapabilitiesProvider, ILspLoggerFactory lspLoggerFactory, IThreadingContext threadingContext) - : base(csharpVBRequestDispatcherFactory, globalOptions, diagnosticService: null, listenerProvider, lspWorkspaceRegistrationService, lspLoggerFactory, threadingContext, diagnosticsClientName: null) + : base(csharpVBRequestDispatcherFactory, globalOptions, listenerProvider, lspWorkspaceRegistrationService, lspLoggerFactory, threadingContext, diagnosticsClientName: null) { _defaultCapabilitiesProvider = defaultCapabilitiesProvider; } protected override ImmutableArray SupportedLanguages => ProtocolConstants.RoslynLspLanguages; - public override string Name => CSharpVisualBasicLanguageServerFactory.UserVisibleName; - public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) { var serverCapabilities = new VSInternalServerCapabilities(); @@ -117,5 +115,7 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa /// as the failure is not catastrophic. /// public override bool ShowNotificationOnInitializeFailed => GlobalOptions.IsPullDiagnostics(InternalDiagnosticsOptions.NormalDiagnosticMode); + + public override WellKnownLspServerKinds ServerKind => WellKnownLspServerKinds.AlwaysActiveVSLspServer; } } diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs index a4913db3c9c21..dc0fb5a92083b 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs @@ -17,6 +17,7 @@ using Roslyn.Utilities; using static Microsoft.CodeAnalysis.CodeActions.CodeAction; using CodeAction = Microsoft.CodeAnalysis.CodeActions.CodeAction; +using CodeActionOptions = Microsoft.CodeAnalysis.CodeActions.CodeActionOptions; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions @@ -33,12 +34,13 @@ public static async Task GetVSCodeActionsAsync( CodeActionParams request, CodeActionsCache codeActionsCache, Document document, + CodeActionOptions options, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, CancellationToken cancellationToken) { var actionSets = await GetActionSetsAsync( - document, codeFixService, codeRefactoringService, request.Range, cancellationToken).ConfigureAwait(false); + document, options, codeFixService, codeRefactoringService, request.Range, cancellationToken).ConfigureAwait(false); if (actionSets.IsDefaultOrEmpty) return Array.Empty(); @@ -158,12 +160,13 @@ public static async Task> GetCodeActionsAsync( CodeActionsCache codeActionsCache, Document document, LSP.Range selection, + CodeActionOptions options, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, CancellationToken cancellationToken) { var actionSets = await GetActionSetsAsync( - document, codeFixService, codeRefactoringService, selection, cancellationToken).ConfigureAwait(false); + document, options, codeFixService, codeRefactoringService, selection, cancellationToken).ConfigureAwait(false); if (actionSets.IsDefaultOrEmpty) return ImmutableArray.Empty; @@ -213,6 +216,7 @@ private static CodeAction GetNestedActionsFromActionSet(IUnifiedSuggestedAction private static async ValueTask> GetActionSetsAsync( Document document, + CodeActionOptions options, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, LSP.Range selection, @@ -224,13 +228,14 @@ private static async ValueTask> GetAct var codeFixes = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( document.Project.Solution.Workspace, codeFixService, document, textSpan, CodeActionRequestPriority.None, - isBlocking: false, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + options, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); var codeRefactorings = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, CodeActionRequestPriority.None, isBlocking: false, + document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, CodeActionRequestPriority.None, options, addOperationScope: _ => null, filterOutsideSelection: false, cancellationToken).ConfigureAwait(false); - var actionSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(codeFixes, codeRefactorings, textSpan, currentActionCount: 0); + var actionSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets( + codeFixes, codeRefactorings, textSpan, currentActionCount: 0); return actionSets; } diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs index 2ef85dfe62d97..c1f6506a0e1d8 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -36,15 +37,18 @@ internal class CodeActionResolveHandler : IRequestHandler LSP.Methods.CodeActionResolveName; @@ -63,10 +67,13 @@ public CodeActionResolveHandler( var data = ((JToken)codeAction.Data!).ToObject(); Assumes.Present(data); + var options = _globalOptions.GetCodeActionOptions(document.Project.Language, isBlocking: false); + var codeActions = await CodeActionHelpers.GetCodeActionsAsync( _codeActionsCache, document, data.Range, + options, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs index 828ad765131ef..4ee968b6db505 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs @@ -5,9 +5,11 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Utilities; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -28,6 +30,7 @@ internal class CodeActionsHandler : IRequestHandler request.TextDocument; @@ -53,8 +58,10 @@ public CodeActionsHandler( var document = context.Document; Contract.ThrowIfNull(document); + var options = _globalOptions.GetCodeActionOptions(document.Project.Language, isBlocking: false); + var codeActions = await CodeActionHelpers.GetVSCodeActionsAsync( - request, _codeActionsCache, document, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false); + request, _codeActionsCache, document, options, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false); return codeActions; } diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionsHandlerProvider.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionsHandlerProvider.cs index 3974678eabc86..1c5a2bd63f08a 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionsHandlerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionsHandlerProvider.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; using Microsoft.CodeAnalysis.LanguageServer.Handler.Commands; +using Microsoft.CodeAnalysis.Options; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler @@ -28,26 +29,29 @@ internal class CodeActionsHandlerProvider : AbstractRequestHandlerProvider private readonly ICodeFixService _codeFixService; private readonly ICodeRefactoringService _codeRefactoringService; private readonly IThreadingContext _threadingContext; + private readonly IGlobalOptionService _globalOptions; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CodeActionsHandlerProvider( ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, - IThreadingContext threadingContext) + IThreadingContext threadingContext, + IGlobalOptionService globalOptions) { _codeFixService = codeFixService; _codeRefactoringService = codeRefactoringService; _threadingContext = threadingContext; + _globalOptions = globalOptions; } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { var codeActionsCache = new CodeActionsCache(); return ImmutableArray.Create( - new CodeActionsHandler(codeActionsCache, _codeFixService, _codeRefactoringService), - new CodeActionResolveHandler(codeActionsCache, _codeFixService, _codeRefactoringService), - new RunCodeActionHandler(codeActionsCache, _codeFixService, _codeRefactoringService, _threadingContext)); + new CodeActionsHandler(codeActionsCache, _codeFixService, _codeRefactoringService, _globalOptions), + new CodeActionResolveHandler(codeActionsCache, _codeFixService, _codeRefactoringService, _globalOptions), + new RunCodeActionHandler(codeActionsCache, _codeFixService, _codeRefactoringService, _globalOptions, _threadingContext)); } } } diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs index a272423c3de19..60412280af531 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs @@ -5,11 +5,13 @@ 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.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; using Microsoft.CodeAnalysis.LanguageServer.Handler.Commands; +using Microsoft.CodeAnalysis.Options; using Newtonsoft.Json.Linq; using Roslyn.Utilities; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -33,17 +35,20 @@ internal class RunCodeActionHandler : AbstractExecuteWorkspaceCommandHandler private readonly CodeActionsCache _codeActionsCache; private readonly ICodeFixService _codeFixService; private readonly ICodeRefactoringService _codeRefactoringService; + private readonly IGlobalOptionService _globalOptions; private readonly IThreadingContext _threadingContext; public RunCodeActionHandler( CodeActionsCache codeActionsCache, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, + IGlobalOptionService globalOptions, IThreadingContext threadingContext) { _codeActionsCache = codeActionsCache; _codeFixService = codeFixService; _codeRefactoringService = codeRefactoringService; + _globalOptions = globalOptions; _threadingContext = threadingContext; } @@ -68,8 +73,10 @@ public override async Task HandleRequestAsync(LSP.ExecuteCommandParams r var runRequest = ((JToken)request.Arguments.Single()).ToObject(); Assumes.Present(runRequest); + var options = _globalOptions.GetCodeActionOptions(document.Project.Language, isBlocking: false); + var codeActions = await CodeActionHelpers.GetCodeActionsAsync( - _codeActionsCache, document, runRequest.Range, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false); + _codeActionsCache, document, runRequest.Range, options, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false); var actionToRun = CodeActionHelpers.GetCodeActionToResolve(runRequest.UniqueIdentifier, codeActions); Contract.ThrowIfNull(actionToRun); diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionHandler.cs index a36e7233ecb2e..1555f67c15d53 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionHandler.cs @@ -454,9 +454,9 @@ static void PromoteCommonCommitCharactersOntoList(LSP.VSInternalCompletionList c CompletionListCache completionListCache, CancellationToken cancellationToken) { - var (completionList, _) = await completionService.GetCompletionsInternalAsync(document, position, completionOptions, completionTrigger, cancellationToken: cancellationToken).ConfigureAwait(false); + var completionList = await completionService.GetCompletionsAsync(document, position, completionOptions, document.Project.Solution.Options, completionTrigger, cancellationToken: cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - if (completionList == null || completionList.Items.IsEmpty) + if (completionList.Items.IsEmpty) { return null; } @@ -545,21 +545,18 @@ private static bool ShouldItemBePreselected(CompletionItem completionItem) return completionItem.Rules.MatchPriority == MatchPriority.Preselect && completionItem.Rules.SelectionBehavior == CompletionItemSelectionBehavior.HardSelection; } - internal static CompletionOptions GetCompletionOptions(Document document) + internal CompletionOptions GetCompletionOptions(Document document) { - // Filter out snippets as they are not supported in the LSP client - // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1139740 // Filter out unimported types for now as there are two issues with providing them: // 1. LSP client does not currently provide a way to provide detail text on the completion item to show the namespace. // https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1076759 // 2. We need to figure out how to provide the text edits along with the completion item or provide them in the resolve request. // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/985860/ // 3. LSP client should support completion filters / expanders - return CompletionOptions.From(document.Project) with + return _globalOptions.GetCompletionOptions(document.Project.Language) with { - SnippetsBehavior = SnippetsRule.NeverInclude, ShowItemsFromUnimportedNamespaces = false, - IsExpandedCompletion = false + ExpandedCompletionBehavior = ExpandedCompletionMode.NonExpandedItemsOnly }; } diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionHandlerProvider.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionHandlerProvider.cs index 6faf4faf44ce1..aafc5da24a766 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionHandlerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionHandlerProvider.cs @@ -33,12 +33,12 @@ public CompletionHandlerProvider( _completionProviders = completionProviders; } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { var completionListCache = new CompletionListCache(); return ImmutableArray.Create( new CompletionHandler(_globalOptions, _completionProviders, completionListCache), - new CompletionResolveHandler(completionListCache)); + new CompletionResolveHandler(_globalOptions, completionListCache)); } } } diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionResolveHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionResolveHandler.cs index e5c2f5e10833e..c37774864dc6f 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionResolveHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Completion/CompletionResolveHandler.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Text.Adornments; using Newtonsoft.Json.Linq; using Roslyn.Utilities; @@ -24,17 +25,19 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler /// references to VS icon types and classified text runs are removed. /// See https://github.com/dotnet/roslyn/issues/55142 /// - internal class CompletionResolveHandler : IRequestHandler + internal sealed class CompletionResolveHandler : IRequestHandler { private readonly CompletionListCache _completionListCache; + private readonly IGlobalOptionService _globalOptions; public string Method => LSP.Methods.TextDocumentCompletionResolveName; public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; - public CompletionResolveHandler(CompletionListCache completionListCache) + public CompletionResolveHandler(IGlobalOptionService globalOptions, CompletionListCache completionListCache) { + _globalOptions = globalOptions; _completionListCache = completionListCache; } @@ -64,7 +67,7 @@ public CompletionResolveHandler(CompletionListCache completionListCache) return completionItem; } - var options = CompletionOptions.From(document.Project); + var options = _globalOptions.GetCompletionOptions(document.Project.Language); var displayOptions = SymbolDescriptionOptions.From(document.Project); var description = await completionService.GetDescriptionAsync(document, selectedItem, options, displayOptions, cancellationToken).ConfigureAwait(false)!; if (description != null) diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Hover/HoverHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Hover/HoverHandler.cs index 3215e315fbe16..8af9a9e84fd97 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Hover/HoverHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Hover/HoverHandler.cs @@ -49,9 +49,9 @@ public HoverHandler() Contract.ThrowIfNull(document); var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); - var quickInfoService = document.Project.LanguageServices.GetRequiredService(); - var info = await quickInfoService.GetQuickInfoAsync(document, position, cancellationToken).ConfigureAwait(false); + var options = SymbolDescriptionOptions.From(document.Project); + var info = await quickInfoService.GetQuickInfoAsync(document, position, options, cancellationToken).ConfigureAwait(false); if (info == null) { return null; diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindAllReferencesHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindAllReferencesHandler.cs index 8067d13083f73..858a994a40d2e 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindAllReferencesHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindAllReferencesHandler.cs @@ -7,10 +7,11 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol; using Microsoft.CodeAnalysis.MetadataAsSource; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -31,15 +32,18 @@ internal class FindAllReferencesHandler : AbstractStatelessRequestHandler LSP.Methods.TextDocumentReferencesName; @@ -63,10 +67,10 @@ public FindAllReferencesHandler( ProtocolConversions.PositionToLinePosition(referenceParams.Position), cancellationToken).ConfigureAwait(false); var findUsagesContext = new FindUsagesLSPContext( - progress, document, position, _metadataAsSourceFileService, _asyncListener, cancellationToken); + progress, document, position, _metadataAsSourceFileService, _asyncListener, _globalOptions, cancellationToken); // Finds the references for the symbol at the specific position in the document, reporting them via streaming to the LSP client. - await findUsagesService.FindReferencesAsync(document, position, findUsagesContext, cancellationToken).ConfigureAwait(false); + await findUsagesService.FindReferencesAsync(findUsagesContext, document, position, cancellationToken).ConfigureAwait(false); await findUsagesContext.OnCompletedAsync(cancellationToken).ConfigureAwait(false); return progress.GetValues(); diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindImplementationsHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindImplementationsHandler.cs index 1f250f7c45e46..f999ac967aa35 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindImplementationsHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindImplementationsHandler.cs @@ -5,8 +5,9 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -16,12 +17,15 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [ExportRoslynLanguagesLspRequestHandlerProvider, Shared] [ProvidesMethod(LSP.Methods.TextDocumentImplementationName)] - internal class FindImplementationsHandler : AbstractStatelessRequestHandler + internal sealed class FindImplementationsHandler : AbstractStatelessRequestHandler { + private readonly IGlobalOptionService _globalOptions; + [ImportingConstructor] [System.Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public FindImplementationsHandler() + public FindImplementationsHandler(IGlobalOptionService globalOptions) { + _globalOptions = globalOptions; } public override string Method => LSP.Methods.TextDocumentImplementationName; @@ -41,8 +45,8 @@ public FindImplementationsHandler() var findUsagesService = document.GetRequiredLanguageService(); var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); - var findUsagesContext = new SimpleFindUsagesContext(); - await FindImplementationsAsync(findUsagesService, document, position, findUsagesContext, cancellationToken).ConfigureAwait(false); + var findUsagesContext = new SimpleFindUsagesContext(_globalOptions); + await findUsagesService.FindImplementationsAsync(findUsagesContext, document, position, cancellationToken).ConfigureAwait(false); foreach (var definition in findUsagesContext.GetDefinitions()) { @@ -62,8 +66,5 @@ public FindImplementationsHandler() return locations.ToArrayAndFree(); } - - protected virtual Task FindImplementationsAsync(IFindUsagesService findUsagesService, Document document, int position, SimpleFindUsagesContext context, CancellationToken cancellationToken) - => findUsagesService.FindImplementationsAsync(document, position, context, cancellationToken); } } diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindUsagesLSPContext.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindUsagesLSPContext.cs index 59f7a8875cc37..3da4dac625de0 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindUsagesLSPContext.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/References/FindUsagesLSPContext.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.FindSymbols.Finders; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.MetadataAsSource; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -27,12 +28,13 @@ namespace Microsoft.CodeAnalysis.LanguageServer.CustomProtocol { - internal class FindUsagesLSPContext : FindUsagesContext + internal sealed class FindUsagesLSPContext : FindUsagesContext { private readonly IProgress _progress; private readonly Document _document; private readonly int _position; private readonly IMetadataAsSourceFileService _metadataAsSourceFileService; + private readonly IGlobalOptionService _globalOptions; /// /// Methods in FindUsagesLSPContext can be called by multiple threads concurrently. @@ -75,16 +77,21 @@ public FindUsagesLSPContext( int position, IMetadataAsSourceFileService metadataAsSourceFileService, IAsynchronousOperationListener asyncListener, + IGlobalOptionService globalOptions, CancellationToken cancellationToken) { _progress = progress; _document = document; _position = position; _metadataAsSourceFileService = metadataAsSourceFileService; + _globalOptions = globalOptions; _workQueue = new AsyncBatchingWorkQueue( TimeSpan.FromMilliseconds(500), ReportReferencesAsync, asyncListener, cancellationToken); } + public override ValueTask GetOptionsAsync(string language, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetFindUsagesOptions(language)); + // After all definitions/references have been found, wait here until all results have been reported. public override async ValueTask OnCompletedAsync(CancellationToken cancellationToken) => await _workQueue.WaitUntilCurrentBatchCompletesAsync().ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Rename/RenameHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Rename/RenameHandler.cs index 0b623be85f463..64ef0497596c5 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Rename/RenameHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Rename/RenameHandler.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Utilities; @@ -53,8 +54,14 @@ public RenameHandler() return null; } - var renameLocationSet = await renameInfo.FindRenameLocationsAsync(oldSolution.Options, cancellationToken).ConfigureAwait(false); - var renameReplacementInfo = await renameLocationSet.GetReplacementsAsync(request.NewName, oldSolution.Options, cancellationToken).ConfigureAwait(false); + var options = new SymbolRenameOptions( + RenameOverloads: false, + RenameInStrings: false, + RenameInComments: false, + RenameFile: false); + + var renameLocationSet = await renameInfo.FindRenameLocationsAsync(options, cancellationToken).ConfigureAwait(false); + var renameReplacementInfo = await renameLocationSet.GetReplacementsAsync(request.NewName, options, cancellationToken).ConfigureAwait(false); var renamedSolution = renameReplacementInfo.NewSolution; var solutionChanges = renamedSolution.GetChanges(oldSolution); diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Symbols/WorkspaceSymbolsHandler.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Symbols/WorkspaceSymbolsHandler.cs index bff75eab9ea0a..70c84edb1d134 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Symbols/WorkspaceSymbolsHandler.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/Symbols/WorkspaceSymbolsHandler.cs @@ -98,7 +98,6 @@ public async Task AddItemAsync(Project project, INavigateToSearchResult result, if (location == null) return; - Contract.ThrowIfNull(location); _progress.Report(new VSSymbolInformation { Name = result.Name, diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/LiveShareInProcLanguageClient.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/LiveShareInProcLanguageClient.cs index f54458d0a289c..b7be5bf149e8c 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/LiveShareInProcLanguageClient.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/LiveShareInProcLanguageClient.cs @@ -32,21 +32,18 @@ internal class LiveShareInProcLanguageClient : AbstractInProcLanguageClient public LiveShareInProcLanguageClient( RequestDispatcherFactory csharpVBRequestDispatcherFactory, IGlobalOptionService globalOptions, - IDiagnosticService diagnosticService, IAsynchronousOperationListenerProvider listenerProvider, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, DefaultCapabilitiesProvider defaultCapabilitiesProvider, ILspLoggerFactory lspLoggerFactory, IThreadingContext threadingContext) - : base(csharpVBRequestDispatcherFactory, globalOptions, diagnosticService, listenerProvider, lspWorkspaceRegistrationService, lspLoggerFactory, threadingContext, diagnosticsClientName: null) + : base(csharpVBRequestDispatcherFactory, globalOptions, listenerProvider, lspWorkspaceRegistrationService, lspLoggerFactory, threadingContext, diagnosticsClientName: null) { _defaultCapabilitiesProvider = defaultCapabilitiesProvider; } protected override ImmutableArray SupportedLanguages => ProtocolConstants.RoslynLspLanguages; - public override string Name => "Live Share C#/Visual Basic Language Server Client"; - public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) { var isLspEditorEnabled = GlobalOptions.GetOption(LspOptions.LspEditorFeatureFlag); @@ -76,6 +73,15 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa defaultCapabilities.SemanticTokensOptions = null; } + // When the lsp pull diagnostics feature flag is enabled we do not advertise pull diagnostics capabilities from here + // as the AlwaysActivateInProcLanguageClient will provide pull diagnostics both locally and remote. + var isPullDiagnosticsEnabled = GlobalOptions.IsPullDiagnostics(InternalDiagnosticsOptions.NormalDiagnosticMode); + if (!isPullDiagnosticsEnabled) + { + // Pull diagnostics isn't enabled, let the live share server provide pull diagnostics. + ((VSInternalServerCapabilities)defaultCapabilities).SupportsDiagnosticRequests = true; + } + return defaultCapabilities; } @@ -83,5 +89,7 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa /// Failures are catastrophic as liveshare guests will not have language features without this server. /// public override bool ShowNotificationOnInitializeFailed => true; + + public override WellKnownLspServerKinds ServerKind => WellKnownLspServerKinds.LiveShareLspServer; } } diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/RazorInProcLanguageClient.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/RazorInProcLanguageClient.cs index 740543a116908..25c6ca5de7d87 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/RazorInProcLanguageClient.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/RazorInProcLanguageClient.cs @@ -5,10 +5,12 @@ using System; using System.Collections.Immutable; using System.ComponentModel.Composition; +using System.Text.RegularExpressions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.LanguageServer.Client; @@ -43,23 +45,17 @@ internal class RazorInProcLanguageClient : AbstractInProcLanguageClient protected override ImmutableArray SupportedLanguages => ProtocolConstants.RoslynLspLanguages; - /// - /// Gets the name of the language client (displayed in yellow bars). - /// - public override string Name => "Razor C# Language Server Client"; - [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public RazorInProcLanguageClient( RequestDispatcherFactory csharpVBRequestDispatcherFactory, IGlobalOptionService globalOptions, - IDiagnosticService diagnosticService, IAsynchronousOperationListenerProvider listenerProvider, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, DefaultCapabilitiesProvider defaultCapabilitiesProvider, IThreadingContext threadingContext, ILspLoggerFactory lspLoggerFactory) - : base(csharpVBRequestDispatcherFactory, globalOptions, diagnosticService, listenerProvider, lspWorkspaceRegistrationService, lspLoggerFactory, threadingContext, ClientName) + : base(csharpVBRequestDispatcherFactory, globalOptions, listenerProvider, lspWorkspaceRegistrationService, lspLoggerFactory, threadingContext, ClientName) { _defaultCapabilitiesProvider = defaultCapabilitiesProvider; } @@ -73,7 +69,15 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa if (capabilities is VSInternalServerCapabilities vsServerCapabilities) { - vsServerCapabilities.SupportsDiagnosticRequests = GlobalOptions.IsPullDiagnostics(InternalDiagnosticsOptions.RazorDiagnosticMode); + vsServerCapabilities.SupportsDiagnosticRequests = true; + + var regexExpression = string.Join("|", InlineCompletionsHandler.BuiltInSnippets); + var regex = new Regex(regexExpression, RegexOptions.Compiled | RegexOptions.Singleline, TimeSpan.FromSeconds(1)); + vsServerCapabilities.InlineCompletionOptions = new VSInternalInlineCompletionOptions + { + Pattern = regex + }; + return vsServerCapabilities; } @@ -84,5 +88,7 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa /// If the razor server is activated then any failures are catastrophic as no razor c# features will work. /// public override bool ShowNotificationOnInitializeFailed => true; + + public override WellKnownLspServerKinds ServerKind => WellKnownLspServerKinds.RazorLspServer; } } diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/VisualStudioInProcLanguageServer.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/VisualStudioInProcLanguageServer.cs index f4207eca9a3c5..15b75347b2645 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/VisualStudioInProcLanguageServer.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/VisualStudioInProcLanguageServer.cs @@ -3,18 +3,12 @@ // 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; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Utilities; using StreamJsonRpc; @@ -29,14 +23,6 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.LanguageClient /// internal class VisualStudioInProcLanguageServer : LanguageServerTarget { - /// - /// Legacy support for LSP push diagnostics. - /// Work queue responsible for receiving notifications about diagnostic updates and publishing those to - /// interested parties. - /// - private readonly AsyncBatchingWorkQueue _diagnosticsWorkQueue; - private readonly IDiagnosticService? _diagnosticService; - private readonly ImmutableArray _supportedLanguages; internal VisualStudioInProcLanguageServer( @@ -47,54 +33,17 @@ internal VisualStudioInProcLanguageServer( IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider, ILspLogger logger, - IDiagnosticService? diagnosticService, ImmutableArray supportedLanguages, string? clientName, - string userVisibleServerName, - string telemetryServerTypeName) - : base(requestDispatcherFactory, jsonRpc, capabilitiesProvider, workspaceRegistrationService, lspMiscellaneousFilesWorkspace: null, globalOptions, listenerProvider, logger, supportedLanguages, clientName, userVisibleServerName, telemetryServerTypeName) + WellKnownLspServerKinds serverKind) + : base(requestDispatcherFactory, jsonRpc, capabilitiesProvider, workspaceRegistrationService, lspMiscellaneousFilesWorkspace: null, globalOptions, listenerProvider, logger, supportedLanguages, clientName, serverKind) { _supportedLanguages = supportedLanguages; - _diagnosticService = diagnosticService; - - // Dedupe on DocumentId. If we hear about the same document multiple times, we only need to process that id once. - _diagnosticsWorkQueue = new AsyncBatchingWorkQueue( - TimeSpan.FromMilliseconds(250), - (ids, ct) => ProcessDiagnosticUpdatedBatchAsync(_diagnosticService, ids, ct), - EqualityComparer.Default, - Listener, - Queue.CancellationToken); - - if (_diagnosticService != null) - _diagnosticService.DiagnosticsUpdated += DiagnosticService_DiagnosticsUpdated; } public override Task InitializedAsync() { - try - { - Logger?.TraceStart("Initialized"); - - // Publish diagnostics for all open documents immediately following initialization. - PublishOpenFileDiagnostics(); - - return Task.CompletedTask; - } - finally - { - Logger?.TraceStop("Initialized"); - } - - void PublishOpenFileDiagnostics() - { - foreach (var workspace in WorkspaceRegistrationService.GetAllRegistrations()) - { - var solution = workspace.CurrentSolution; - var openDocuments = workspace.GetOpenDocumentIds(); - foreach (var documentId in openDocuments) - DiagnosticService_DiagnosticsUpdated(solution, documentId); - } - } + return Task.CompletedTask; } [JsonRpcMethod(VSInternalMethods.DocumentPullDiagnosticName, UseSingleObjectParameterDeserialization = true)] @@ -144,272 +93,13 @@ void PublishOpenFileDiagnostics() renameParams, _clientCapabilities, ClientName, cancellationToken); } - protected override void ShutdownImpl() - { - base.ShutdownImpl(); - if (_diagnosticService != null) - _diagnosticService.DiagnosticsUpdated -= DiagnosticService_DiagnosticsUpdated; - } - - private void DiagnosticService_DiagnosticsUpdated(object? _, DiagnosticsUpdatedArgs e) - => DiagnosticService_DiagnosticsUpdated(e.Solution, e.DocumentId); - - private void DiagnosticService_DiagnosticsUpdated(Solution? solution, DocumentId? documentId) - { - // LSP doesn't support diagnostics without a document. So if we get project level diagnostics without a document, ignore them. - if (documentId != null && solution != null) - { - var document = solution.GetDocument(documentId); - if (document == null || document.FilePath == null) - return; - - // Only publish document diagnostics for the languages this provider supports. - if (!_supportedLanguages.Contains(document.Project.Language)) - return; - - _diagnosticsWorkQueue.AddWork(document.Id); - } - } - - /// - /// Stores the last published LSP diagnostics with the Roslyn document that they came from. - /// This is useful in the following scenario. Imagine we have documentA which has contributions to mapped files m1 and m2. - /// dA -> m1 - /// And m1 has contributions from documentB. - /// m1 -> dA, dB - /// When we query for diagnostic on dA, we get a subset of the diagnostics on m1 (missing the contributions from dB) - /// Since each publish diagnostics notification replaces diagnostics per document, - /// we must union the diagnostics contribution from dB and dA to produce all diagnostics for m1 and publish all at once. - /// - /// This dictionary stores the previously computed diagnostics for the published file so that we can - /// union the currently computed diagnostics (e.g. for dA) with previously computed diagnostics (e.g. from dB). - /// - private readonly Dictionary>> _publishedFileToDiagnostics = new(); - - /// - /// Stores the mapping of a document to the uri(s) of diagnostics previously produced for this document. When - /// we get empty diagnostics for the document we need to find the uris we previously published for this - /// document. Then we can publish the updated diagnostics set for those uris (either empty or the diagnostic - /// contributions from other documents). We use a sorted set to ensure consistency in the order in which we - /// report URIs. While it's not necessary to publish a document's mapped file diagnostics in a particular - /// order, it does make it much easier to write tests and debug issues if we have a consistent ordering. - /// - private readonly Dictionary> _documentsToPublishedUris = new(); - - /// - /// Basic comparer for Uris used by when publishing notifications. - /// - private static readonly Comparer s_uriComparer = Comparer.Create((uri1, uri2) - => Uri.Compare(uri1, uri2, UriComponents.AbsoluteUri, UriFormat.SafeUnescaped, StringComparison.OrdinalIgnoreCase)); - - // internal for testing purposes - internal async ValueTask ProcessDiagnosticUpdatedBatchAsync( - IDiagnosticService? diagnosticService, ImmutableArray documentIds, CancellationToken cancellationToken) - { - if (diagnosticService == null) - return; - - foreach (var documentId in documentIds) - { - cancellationToken.ThrowIfCancellationRequested(); - var document = WorkspaceRegistrationService.GetAllRegistrations().Select(w => w.CurrentSolution.GetDocument(documentId)).FirstOrDefault(); - - if (document != null) - { - // If this is a `pull` client, and `pull` diagnostics is on, then we should not `publish` (push) the - // diagnostics here. - var diagnosticMode = document.IsRazorDocument() - ? InternalDiagnosticsOptions.RazorDiagnosticMode - : InternalDiagnosticsOptions.NormalDiagnosticMode; - if (GlobalOptions.IsPushDiagnostics(diagnosticMode)) - await PublishDiagnosticsAsync(diagnosticService, document, cancellationToken).ConfigureAwait(false); - } - } - } - - private async Task PublishDiagnosticsAsync(IDiagnosticService diagnosticService, Document document, CancellationToken cancellationToken) - { - // Retrieve all diagnostics for the current document grouped by their actual file uri. - var fileUriToDiagnostics = await GetDiagnosticsAsync(diagnosticService, document, cancellationToken).ConfigureAwait(false); - - // Get the list of file uris with diagnostics (for the document). - // We need to join the uris from current diagnostics with those previously published - // so that we clear out any diagnostics in mapped files that are no longer a part - // of the current diagnostics set (because the diagnostics were fixed). - // Use sorted set to have consistent publish ordering for tests and debugging. - var urisForCurrentDocument = _documentsToPublishedUris.GetValueOrDefault(document.Id, ImmutableSortedSet.Create(s_uriComparer)).Union(fileUriToDiagnostics.Keys); - - // Update the mapping for this document to be the uris we're about to publish diagnostics for. - _documentsToPublishedUris[document.Id] = urisForCurrentDocument; - - // Go through each uri and publish the updated set of diagnostics per uri. - foreach (var fileUri in urisForCurrentDocument) - { - // Get the updated diagnostics for a single uri that were contributed by the current document. - var diagnostics = fileUriToDiagnostics.GetValueOrDefault(fileUri, ImmutableArray.Empty); - - if (_publishedFileToDiagnostics.ContainsKey(fileUri)) - { - // Get all previously published diagnostics for this uri excluding those that were contributed from the current document. - // We don't need those since we just computed the updated values above. - var diagnosticsFromOtherDocuments = _publishedFileToDiagnostics[fileUri].Where(kvp => kvp.Key != document.Id).SelectMany(kvp => kvp.Value); - - // Since diagnostics are replaced per uri, we must publish both contributions from this document and any other document - // that has diagnostic contributions to this uri, so union the two sets. - diagnostics = diagnostics.AddRange(diagnosticsFromOtherDocuments); - } - - await SendDiagnosticsNotificationAsync(fileUri, diagnostics).ConfigureAwait(false); - - // There are three cases here -> - // 1. There are no diagnostics to publish for this fileUri. We no longer need to track the fileUri at all. - // 2. There are diagnostics from the current document. Store the diagnostics for the fileUri and document - // so they can be published along with contributions to the fileUri from other documents. - // 3. There are no diagnostics contributed by this document to the fileUri (could be some from other documents). - // We should clear out the diagnostics for this document for the fileUri. - if (diagnostics.IsEmpty) - { - // We published an empty set of diagnostics for this uri. We no longer need to keep track of this mapping - // since there will be no previous diagnostics that we need to clear out. - _documentsToPublishedUris.MultiRemove(document.Id, fileUri); - - // There are not any diagnostics to keep track of for this file, so we can stop. - _publishedFileToDiagnostics.Remove(fileUri); - } - else if (fileUriToDiagnostics.ContainsKey(fileUri)) - { - // We do have diagnostics from the current document - update the published diagnostics map - // to contain the new diagnostics contributed by this document for this uri. - var documentsToPublishedDiagnostics = _publishedFileToDiagnostics.GetOrAdd(fileUri, (_) => - new Dictionary>()); - documentsToPublishedDiagnostics[document.Id] = fileUriToDiagnostics[fileUri]; - } - else - { - // There were diagnostics from other documents, but none from the current document. - // If we're tracking the current document, we can stop. - IReadOnlyDictionaryExtensions.GetValueOrDefault(_publishedFileToDiagnostics, fileUri)?.Remove(document.Id); - _documentsToPublishedUris.MultiRemove(document.Id, fileUri); - } - } - } - - private async Task SendDiagnosticsNotificationAsync(Uri uri, ImmutableArray diagnostics) - { - var publishDiagnosticsParams = new PublishDiagnosticParams { Diagnostics = diagnostics.ToArray(), Uri = uri }; - await JsonRpc.NotifyWithParameterObjectAsync(Methods.TextDocumentPublishDiagnosticsName, publishDiagnosticsParams).ConfigureAwait(false); - } - - private async Task>> GetDiagnosticsAsync( - IDiagnosticService diagnosticService, Document document, CancellationToken cancellationToken) - { - var option = document.IsRazorDocument() - ? InternalDiagnosticsOptions.RazorDiagnosticMode - : InternalDiagnosticsOptions.NormalDiagnosticMode; - var pushDiagnostics = await diagnosticService.GetPushDiagnosticsAsync(document.Project.Solution.Workspace, document.Project.Id, document.Id, id: null, includeSuppressedDiagnostics: false, option, cancellationToken).ConfigureAwait(false); - var diagnostics = pushDiagnostics.WhereAsArray(IncludeDiagnostic); - - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - - // Retrieve diagnostics for the document. These diagnostics could be for the current document, or they could map - // to a different location in a different file. We need to publish the diagnostics for the mapped locations as well. - // An example of this is razor imports where the generated C# document maps to many razor documents. - // https://docs.microsoft.com/en-us/aspnet/core/mvc/views/layout?view=aspnetcore-3.1#importing-shared-directives - // https://docs.microsoft.com/en-us/aspnet/core/blazor/layouts?view=aspnetcore-3.1#centralized-layout-selection - // So we get the diagnostics and group them by the actual mapped path so we can publish notifications - // for each mapped file's diagnostics. - var fileUriToDiagnostics = diagnostics.GroupBy(diagnostic => GetDiagnosticUri(document, diagnostic)).ToDictionary( - group => group.Key, - group => group.Select(diagnostic => ConvertToLspDiagnostic(diagnostic, text)).ToImmutableArray()); - return fileUriToDiagnostics; - - static Uri GetDiagnosticUri(Document document, DiagnosticData diagnosticData) - { - Contract.ThrowIfNull(diagnosticData.DataLocation, "Diagnostic data location should not be null here"); - - // Razor wants to handle all span mapping themselves. So if we are in razor, return the raw doc spans, and - // do not map them. - var filePath = diagnosticData.DataLocation.MappedFilePath ?? diagnosticData.DataLocation.OriginalFilePath; - return ProtocolConversions.GetUriFromFilePath(filePath); - } - } - - private LSP.Diagnostic ConvertToLspDiagnostic(DiagnosticData diagnosticData, SourceText text) + [JsonRpcMethod(VSInternalMethods.TextDocumentInlineCompletionName, UseSingleObjectParameterDeserialization = true)] + public Task GetInlineCompletionsAsync(VSInternalInlineCompletionRequest request, CancellationToken cancellationToken) { - Contract.ThrowIfNull(diagnosticData.DataLocation); - - var diagnostic = new LSP.Diagnostic - { - Source = TelemetryServerName, - Code = diagnosticData.Id, - Severity = Convert(diagnosticData.Severity), - Range = GetDiagnosticRange(diagnosticData.DataLocation, text), - // Only the unnecessary diagnostic tag is currently supported via LSP. - Tags = diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary) - ? new DiagnosticTag[] { DiagnosticTag.Unnecessary } - : Array.Empty() - }; - - if (diagnosticData.Message != null) - diagnostic.Message = diagnosticData.Message; - - return diagnostic; - } - - private static LSP.DiagnosticSeverity Convert(CodeAnalysis.DiagnosticSeverity severity) - => severity switch - { - CodeAnalysis.DiagnosticSeverity.Hidden => LSP.DiagnosticSeverity.Hint, - CodeAnalysis.DiagnosticSeverity.Info => LSP.DiagnosticSeverity.Hint, - CodeAnalysis.DiagnosticSeverity.Warning => LSP.DiagnosticSeverity.Warning, - CodeAnalysis.DiagnosticSeverity.Error => LSP.DiagnosticSeverity.Error, - _ => throw ExceptionUtilities.UnexpectedValue(severity), - }; - - // Some diagnostics only apply to certain clients and document types, e.g. Razor. - // If the DocumentPropertiesService.DiagnosticsLspClientName property exists, we only include the - // diagnostic if it directly matches the client name. - // If the DocumentPropertiesService.DiagnosticsLspClientName property doesn't exist, - // we know that the diagnostic we're working with is contained in a C#/VB file, since - // if we were working with a non-C#/VB file, then the property should have been populated. - // In this case, unless we have a null client name, we don't want to publish the diagnostic - // (since a null client name represents the C#/VB language server). - private bool IncludeDiagnostic(DiagnosticData diagnostic) - => IReadOnlyDictionaryExtensions.GetValueOrDefault(diagnostic.Properties, nameof(DocumentPropertiesService.DiagnosticsLspClientName)) == ClientName; - - private static LSP.Range GetDiagnosticRange(DiagnosticDataLocation diagnosticDataLocation, SourceText text) - { - var linePositionSpan = DiagnosticData.GetLinePositionSpan(diagnosticDataLocation, text, useMapped: true); - return ProtocolConversions.LinePositionToRange(linePositionSpan); - } - - internal new TestAccessor GetTestAccessor() => new(this); - - internal new readonly struct TestAccessor - { - private readonly VisualStudioInProcLanguageServer _server; - - internal TestAccessor(VisualStudioInProcLanguageServer server) - { - _server = server; - } - - internal ImmutableArray GetFileUrisInPublishDiagnostics() - => _server._publishedFileToDiagnostics.Keys.ToImmutableArray(); - - internal ImmutableArray GetDocumentIdsInPublishedUris() - => _server._documentsToPublishedUris.Keys.ToImmutableArray(); - - internal IImmutableSet GetFileUrisForDocument(DocumentId documentId) - => _server._documentsToPublishedUris.GetValueOrDefault(documentId, ImmutableSortedSet.Empty); - - internal ImmutableArray GetDiagnosticsForUriAndDocument(DocumentId documentId, Uri uri) - { - if (_server._publishedFileToDiagnostics.TryGetValue(uri, out var dict) && dict.TryGetValue(documentId, out var diagnostics)) - return diagnostics; + Contract.ThrowIfNull(_clientCapabilities, $"{nameof(InitializeAsync)} has not been called."); - return ImmutableArray.Empty; - } + return RequestDispatcher.ExecuteRequestAsync(Queue, VSInternalMethods.TextDocumentInlineCompletionName, + request, _clientCapabilities, ClientName, cancellationToken); } } } diff --git a/src/EditorFeatures/Core/Implementation/NavigationBar/NavigationBarController.cs b/src/EditorFeatures/Core/Implementation/NavigationBar/NavigationBarController.cs index 7d4858061767c..c9d7440fcc6e1 100644 --- a/src/EditorFeatures/Core/Implementation/NavigationBar/NavigationBarController.cs +++ b/src/EditorFeatures/Core/Implementation/NavigationBar/NavigationBarController.cs @@ -78,14 +78,14 @@ public NavigationBarController( _asyncListener = asyncListener; _computeModelQueue = new AsyncBatchingWorkQueue( - TimeSpan.FromMilliseconds(TaggerConstants.ShortDelay), + DelayTimeSpan.Short, ComputeModelAndSelectItemAsync, EqualityComparer.Default, asyncListener, _cancellationTokenSource.Token); _selectItemQueue = new AsyncBatchingWorkQueue( - TimeSpan.FromMilliseconds(TaggerConstants.NearImmediateDelay), + DelayTimeSpan.NearImmediate, SelectItemAsync, asyncListener, _cancellationTokenSource.Token); diff --git a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCommitter.cs b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCommitter.cs index 2d048440c3e99..6e03146929dbb 100644 --- a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCommitter.cs +++ b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.RenameTrackingCommitter.cs @@ -81,14 +81,8 @@ private async Task RenameSymbolWorkerAsync(Cancellati var symbol = await TryGetSymbolAsync(solutionWithOriginalName, document.Id, cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(symbol, "Invoked rename tracking smart tag but cannot find the symbol."); - var optionSet = document.Project.Solution.Workspace.Options; - - if (_stateMachine.TrackingSession.ForceRenameOverloads) - { - optionSet = optionSet.WithChangedOption(RenameOptions.RenameOverloads, true); - } - - var renamedSolution = await Renamer.RenameSymbolAsync(solutionWithOriginalName, symbol, newName, optionSet, cancellationToken).ConfigureAwait(false); + var options = new SymbolRenameOptions(RenameOverloads: _stateMachine.TrackingSession.ForceRenameOverloads); + var renamedSolution = await Renamer.RenameSymbolAsync(solutionWithOriginalName, symbol, options, newName, cancellationToken).ConfigureAwait(false); return new RenameTrackingSolutionSet(symbol, solutionWithOriginalName, renamedSolution); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionIdOptions.cs b/src/EditorFeatures/Core/Logging/FunctionIdOptions.cs similarity index 73% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionIdOptions.cs rename to src/EditorFeatures/Core/Logging/FunctionIdOptions.cs index 613d02ff52c84..6deb30b927425 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionIdOptions.cs +++ b/src/EditorFeatures/Core/Logging/FunctionIdOptions.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Linq; using System.Collections.Concurrent; using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; @@ -26,5 +27,12 @@ private static Option2 CreateOption(FunctionId id) public static Option2 GetOption(FunctionId id) => s_options.GetOrAdd(id, s_optionCreator); + + public static Func CreateFunctionIsEnabledPredicate(IGlobalOptionService globalOptions) + { + var functionIds = Enum.GetValues(typeof(FunctionId)).Cast(); + var functionIdOptions = functionIds.ToDictionary(id => id, id => globalOptions.GetOption(GetOption(id))); + return functionId => functionIdOptions[functionId]; + } } } diff --git a/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj b/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj index 393a8bbb2f76c..6a935b276cb16 100644 --- a/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj +++ b/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj @@ -22,6 +22,7 @@ + @@ -29,9 +30,7 @@ - - - + + + + + + @@ -106,6 +110,11 @@ + + + + + diff --git a/src/EditorFeatures/Core/Options/ExtensionManagerOptions.cs b/src/EditorFeatures/Core/Options/ExtensionManagerOptions.cs index 5aa30ccad5b63..20b38e3a0c629 100644 --- a/src/EditorFeatures/Core/Options/ExtensionManagerOptions.cs +++ b/src/EditorFeatures/Core/Options/ExtensionManagerOptions.cs @@ -23,7 +23,7 @@ public ExtensionManagerOptions() public ImmutableArray Options { get; } = ImmutableArray.Create( DisableCrashingExtensions); - public static readonly Option DisableCrashingExtensions = new( + public static readonly Option2 DisableCrashingExtensions = new( nameof(ExtensionManagerOptions), nameof(DisableCrashingExtensions), defaultValue: true); } } diff --git a/src/EditorFeatures/Core/PublicAPI.Shipped.txt b/src/EditorFeatures/Core/PublicAPI.Shipped.txt index 8b581ef31f58f..e69de29bb2d1d 100644 --- a/src/EditorFeatures/Core/PublicAPI.Shipped.txt +++ b/src/EditorFeatures/Core/PublicAPI.Shipped.txt @@ -1,2 +0,0 @@ -Microsoft.CodeAnalysis.Editor.Peek.IPeekableItemFactory -Microsoft.CodeAnalysis.Editor.Peek.IPeekableItemFactory.GetPeekableItemsAsync(Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Project project, Microsoft.VisualStudio.Language.Intellisense.IPeekResultFactory peekResultFactory, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task> diff --git a/src/EditorFeatures/Core/PublicAPI.Unshipped.txt b/src/EditorFeatures/Core/PublicAPI.Unshipped.txt index cbc6a71b7f3ab..8b137891791fe 100644 --- a/src/EditorFeatures/Core/PublicAPI.Unshipped.txt +++ b/src/EditorFeatures/Core/PublicAPI.Unshipped.txt @@ -1,2 +1 @@ -*REMOVED*Microsoft.CodeAnalysis.Editor.Peek.IPeekableItemFactory -*REMOVED*Microsoft.CodeAnalysis.Editor.Peek.IPeekableItemFactory.GetPeekableItemsAsync(Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Project project, Microsoft.VisualStudio.Language.Intellisense.IPeekResultFactory peekResultFactory, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task> \ No newline at end of file + diff --git a/src/EditorFeatures/Core/Shared/BrowserHelper.cs b/src/EditorFeatures/Core/Shared/BrowserHelper.cs deleted file mode 100644 index 1f9a5e574dabc..0000000000000 --- a/src/EditorFeatures/Core/Shared/BrowserHelper.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.CodeAnalysis.Editor.Shared -{ - internal static class BrowserHelper - { - /// - /// Unique VS session id. - /// Internal for testing. - /// TODO: Revisit - static non-deterministic data https://github.com/dotnet/roslyn/issues/39415 - /// - internal static readonly string EscapedRequestId = Guid.NewGuid().ToString(); - - private const string BingGetApiUrl = "https://bingdev.cloudapp.net/BingUrl.svc/Get"; - private const int BingQueryArgumentMaxLength = 10240; - - private static bool TryGetWellFormedHttpUri(string? link, [NotNullWhen(true)] out Uri? uri) - { - uri = null; - if (string.IsNullOrWhiteSpace(link) || !Uri.IsWellFormedUriString(link, UriKind.Absolute)) - { - return false; - } - - var absoluteUri = new Uri(link, UriKind.Absolute); - if (absoluteUri.Scheme != Uri.UriSchemeHttp && absoluteUri.Scheme != Uri.UriSchemeHttps) - { - return false; - } - - uri = absoluteUri; - return true; - } - - public static Uri? GetHelpLink(DiagnosticDescriptor descriptor, string language) - => GetHelpLink(descriptor.Id, descriptor.GetBingHelpMessage(), language, descriptor.HelpLinkUri); - - public static Uri? GetHelpLink(DiagnosticData data) - => GetHelpLink(data.Id, data.ENUMessageForBingSearch, data.Language, data.HelpLink); - - private static Uri? GetHelpLink(string diagnosticId, string? title, string? language, string? rawHelpLink) - { - if (string.IsNullOrWhiteSpace(diagnosticId)) - { - return null; - } - - if (TryGetWellFormedHttpUri(rawHelpLink, out var link)) - { - return link; - } - - return new Uri(BingGetApiUrl + - "?selectedText=" + EscapeDataString(title) + - "&mainLanguage=" + EscapeDataString(language) + - "&requestId=" + EscapedRequestId + - "&errorCode=" + EscapeDataString(diagnosticId)); - } - - private static string EscapeDataString(string? str) - { - if (str == null) - { - return string.Empty; - } - - try - { - // Uri has limit on string size (32766 characters). - return Uri.EscapeDataString(str.Substring(0, Math.Min(str.Length, BingQueryArgumentMaxLength))); - } - catch (UriFormatException) - { - return string.Empty; - } - } - - public static string? GetHelpLinkToolTip(DiagnosticData data) - { - var helpLink = GetHelpLink(data); - - if (helpLink == null) - { - return null; - } - - return GetHelpLinkToolTip(data.Id, helpLink); - } - - public static string GetHelpLinkToolTip(string diagnosticId, Uri uri) - { - var strUri = uri.ToString(); - - var resourceName = strUri.StartsWith(BingGetApiUrl, StringComparison.Ordinal) ? - EditorFeaturesResources.Get_help_for_0_from_Bing : EditorFeaturesResources.Get_help_for_0; - - // We make sure not to use Uri.AbsoluteUri for the url displayed in the tooltip so that the url displayed in the tooltip stays human readable. - return string.Format(resourceName, diagnosticId) + "\r\n" + strUri; - } - } -} diff --git a/src/EditorFeatures/Core/Shared/Extensions/ITextSnapshotExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/ITextSnapshotExtensions.cs index 1237d796cacf5..4e87d9398d842 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/ITextSnapshotExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/ITextSnapshotExtensions.cs @@ -41,8 +41,11 @@ public static void FormatAndApplyToBuffer(this ITextSnapshot snapshot, TextSpan rules = document.GetFormattingRules(span, rules); var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken); - var documentOptions = document.GetOptionsAsync(cancellationToken).WaitAndGetResult(cancellationToken); - var changes = Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(span), document.Project.Solution.Workspace, documentOptions, rules, cancellationToken); + var formatter = document.GetRequiredLanguageService(); + + var options = SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); + var result = formatter.GetFormattingResult(root, SpecializedCollections.SingletonEnumerable(span), options, rules, cancellationToken); + var changes = result.GetTextChanges(cancellationToken); using (Logger.LogBlock(FunctionId.Formatting_ApplyResultToBuffer, cancellationToken)) { diff --git a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs index d85f1a40347b4..e500cd34fa986 100644 --- a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs +++ b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs @@ -68,6 +68,9 @@ public FeatureOnOffOptions() public static readonly PerLanguageOption2 PrettyListing = new(FeatureName, "PrettyListing", defaultValue: true, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PrettyListing")); + public static readonly PerLanguageOption2 StringIdentation = new(FeatureName, "StringIdentation", defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.StringIdentation")); + public static readonly PerLanguageOption2 RenameTrackingPreview = new(FeatureName, "RenameTrackingPreview", defaultValue: true, storageLocation: new RoamingProfileStorageLocation(language => language == LanguageNames.VisualBasic ? "TextEditor.%LANGUAGE%.Specific.RenameTrackingPreview" : "TextEditor.%LANGUAGE%.Specific.Rename Tracking Preview")); @@ -100,7 +103,7 @@ public FeatureOnOffOptions() FeatureName, "OfferRemoveUnusedReferences", defaultValue: true, storageLocation: new RoamingProfileStorageLocation("TextEditor.OfferRemoveUnusedReferences")); - public static readonly Option OfferRemoveUnusedReferencesFeatureFlag = new( + public static readonly Option2 OfferRemoveUnusedReferencesFeatureFlag = new( FeatureName, "OfferRemoveUnusedReferencesFeatureFlag", defaultValue: false, new FeatureFlagStorageLocation("Roslyn.RemoveUnusedReferences")); diff --git a/src/EditorFeatures/Core/Shared/Options/PerformanceFunctionIdOptionsProvider.cs b/src/EditorFeatures/Core/Shared/Options/PerformanceFunctionIdOptionsProvider.cs deleted file mode 100644 index 488a1aafdf106..0000000000000 --- a/src/EditorFeatures/Core/Shared/Options/PerformanceFunctionIdOptionsProvider.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.PooledObjects; - -namespace Microsoft.CodeAnalysis.Editor.Shared.Options -{ - [ExportGlobalOptionProvider, Shared] - internal sealed class PerformanceFunctionIdOptionsProvider : IOptionProvider - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public PerformanceFunctionIdOptionsProvider() - { - } - - public ImmutableArray Options - { - get - { - using var resultDisposer = ArrayBuilder.GetInstance(out var result); - foreach (var id in (FunctionId[])Enum.GetValues(typeof(FunctionId))) - { - result.Add(FunctionIdOptions.GetOption(id)); - } - - return result.ToImmutable(); - } - } - } -} diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerConstants.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerConstants.cs index 8ace9eb3e26a0..66b0cbd887d79 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerConstants.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerConstants.cs @@ -10,12 +10,6 @@ namespace Microsoft.CodeAnalysis.Editor.Shared.Tagging { internal static class TaggerConstants { - internal const int NearImmediateDelay = 50; - internal const int ShortDelay = 250; - internal const int MediumDelay = 500; - internal const int IdleDelay = 1500; - internal const int NonFocusDelay = 3000; - internal static TimeSpan ComputeTimeDelay(this TaggerDelay behavior, ITextBuffer textBufferOpt) { if (TextBufferAssociatedViewService.AnyAssociatedViewHasFocus(textBufferOpt)) @@ -25,16 +19,16 @@ internal static TimeSpan ComputeTimeDelay(this TaggerDelay behavior, ITextBuffer return ComputeTimeDelay(behavior); } - return TimeSpan.FromMilliseconds(NonFocusDelay); + return DelayTimeSpan.NonFocus; } internal static TimeSpan ComputeTimeDelay(this TaggerDelay behavior) => behavior switch { - TaggerDelay.NearImmediate => TimeSpan.FromMilliseconds(NearImmediateDelay), - TaggerDelay.Short => TimeSpan.FromMilliseconds(ShortDelay), - TaggerDelay.Medium => TimeSpan.FromMilliseconds(MediumDelay), - _ => TimeSpan.FromMilliseconds(IdleDelay), + TaggerDelay.NearImmediate => DelayTimeSpan.NearImmediate, + TaggerDelay.Short => DelayTimeSpan.Short, + TaggerDelay.Medium => DelayTimeSpan.Medium, + _ => DelayTimeSpan.Idle, }; } } diff --git a/src/EditorFeatures/Core/StackTraceExplorer/StackTraceExplorerUtilities.cs b/src/EditorFeatures/Core/StackTraceExplorer/StackTraceExplorerUtilities.cs deleted file mode 100644 index 935901ca01365..0000000000000 --- a/src/EditorFeatures/Core/StackTraceExplorer/StackTraceExplorerUtilities.cs +++ /dev/null @@ -1,207 +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.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; -using Microsoft.CodeAnalysis.EmbeddedLanguages.StackFrame; -using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.StackTraceExplorer; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Editor.StackTraceExplorer -{ - internal static class StackTraceExplorerUtilities - { - public static async Task GetDefinitionAsync(Solution solution, StackFrameCompilationUnit compilationUnit, StackFrameSymbolPart symbolPart, CancellationToken cancellationToken) - { - // MemberAccessExpression is [Expression].[Identifier], and Identifier is the - // method name. - var typeExpression = compilationUnit.MethodDeclaration.MemberAccessExpression.Left; - - // typeExpression.ToString() returns the full expression (or identifier) - // including arity for generic types. - var fullyQualifiedTypeName = typeExpression.ToString(); - - var typeName = typeExpression is StackFrameQualifiedNameNode qualifiedName - ? qualifiedName.Right.ToString() - : typeExpression.ToString(); - - RoslynDebug.AssertNotNull(fullyQualifiedTypeName); - - var methodIdentifier = compilationUnit.MethodDeclaration.MemberAccessExpression.Right; - var methodTypeArguments = compilationUnit.MethodDeclaration.TypeArguments; - var methodArguments = compilationUnit.MethodDeclaration.ArgumentList; - - var methodName = methodIdentifier.ToString(); - - // - // Do a first pass to find projects with the type name to check first - // - using var _ = PooledObjects.ArrayBuilder.GetInstance(out var candidateProjects); - foreach (var project in solution.Projects) - { - if (!project.SupportsCompilation) - { - continue; - } - - var containsSymbol = await project.ContainsSymbolsWithNameAsync( - typeName, - SymbolFilter.Type, - cancellationToken).ConfigureAwait(false); - - if (containsSymbol) - { - var matchingMethods = await GetMatchingMembersFromCompilationAsync(project).ConfigureAwait(false); - if (matchingMethods.Any()) - { - return await GetDefinitionAsync(matchingMethods[0]).ConfigureAwait(false); - } - } - else - { - candidateProjects.Add(project); - } - } - - // - // Do a second pass to check the remaining compilations - // for the symbol, which may be a metadata symbol in the compilation - // - foreach (var project in candidateProjects) - { - var matchingMethods = await GetMatchingMembersFromCompilationAsync(project).ConfigureAwait(false); - if (matchingMethods.Any()) - { - return await GetDefinitionAsync(matchingMethods[0]).ConfigureAwait(false); - } - } - - return null; - - // - // Local Functions - // - - async Task> GetMatchingMembersFromCompilationAsync(Project project) - { - var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - var type = compilation.GetTypeByMetadataName(fullyQualifiedTypeName); - if (type is null) - { - return ImmutableArray.Empty; - } - - var members = type.GetMembers(); - return members - .OfType() - .Where(m => m.Name == methodName) - .Where(m => MatchTypeArguments(m.TypeArguments, methodTypeArguments)) - .Where(m => MatchParameters(m.Parameters, methodArguments)) - .ToImmutableArrayOrEmpty(); - } - - Task GetDefinitionAsync(IMethodSymbol method) - { - ISymbol symbol = method; - if (symbolPart == StackFrameSymbolPart.ContainingType) - { - symbol = method.ContainingType; - } - - return symbol.ToNonClassifiedDefinitionItemAsync(solution, includeHiddenLocations: true, cancellationToken); - } - } - - private static bool MatchParameters(ImmutableArray parameters, StackFrameParameterList stackFrameParameters) - { - if (parameters.Length != stackFrameParameters.Parameters.Length) - { - return false; - } - - for (var i = 0; i < stackFrameParameters.Parameters.Length; i++) - { - var stackFrameParameter = stackFrameParameters.Parameters[i]; - var paramSymbol = parameters[i]; - - if (paramSymbol.Name != stackFrameParameter.Identifier.ToString()) - { - return false; - } - - if (!MatchType(paramSymbol.Type, stackFrameParameter.Type)) - { - return false; - } - } - - return true; - } - - private static bool MatchTypeArguments(ImmutableArray typeArguments, StackFrameTypeArgumentList? stackFrameTypeArgumentList) - { - if (stackFrameTypeArgumentList is null) - { - return typeArguments.IsEmpty; - } - - if (typeArguments.IsEmpty) - { - return false; - } - - var stackFrameTypeArguments = stackFrameTypeArgumentList.TypeArguments; - return typeArguments.Length == stackFrameTypeArguments.Length; - } - - private static bool MatchType(ITypeSymbol type, StackFrameTypeNode stackFrameType) - { - if (type is IArrayTypeSymbol arrayType) - { - if (stackFrameType is not StackFrameArrayTypeNode arrayTypeNode) - { - return false; - } - - ITypeSymbol currentType = arrayType; - - // Iterate through each array expression and make sure the dimensions - // match the element types in an array. - // Ex: string[,][] - // [,] is a 2 dimension array with element type string[] - // [] is a 1 dimension array with element type string - foreach (var arrayExpression in arrayTypeNode.ArrayRankSpecifiers) - { - if (currentType is not IArrayTypeSymbol currentArrayType) - { - return false; - } - - if (currentArrayType.Rank != arrayExpression.CommaTokens.Length + 1) - { - return false; - } - - currentType = currentArrayType.ElementType; - } - - // All array types have been exchausted from the - // stackframe identifier and the type is still an array - if (currentType is IArrayTypeSymbol) - { - return false; - } - - return MatchType(currentType, arrayTypeNode.TypeIdentifier); - } - - return type.Name == stackFrameType.ToString(); - } - } -} diff --git a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchOptionsStorage.cs b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchOptionsStorage.cs new file mode 100644 index 0000000000000..fbd8903617613 --- /dev/null +++ b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchOptionsStorage.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.SymbolSearch +{ + internal static class SymbolSearchOptionsStorage + { + internal static SymbolSearchOptions GetSymbolSearchOptions(this IGlobalOptionService globalOptions, string language) + => new( + SearchReferenceAssemblies: globalOptions.GetOption(SearchReferenceAssemblies, language), + SearchNuGetPackages: globalOptions.GetOption(SearchNuGetPackages, language)); + + private const string FeatureName = "SymbolSearchOptions"; + + public static PerLanguageOption2 SearchReferenceAssemblies = + new(FeatureName, "SuggestForTypesInReferenceAssemblies", SymbolSearchOptions.Default.SearchReferenceAssemblies, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SuggestForTypesInReferenceAssemblies")); + + public static PerLanguageOption2 SearchNuGetPackages = + new(FeatureName, "SuggestForTypesInNuGetPackages", SymbolSearchOptions.Default.SearchNuGetPackages, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SuggestForTypesInNuGetPackages")); + } +} diff --git a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs deleted file mode 100644 index bc379cfbf7c7b..0000000000000 --- a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Immutable; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Remote; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.SymbolSearch -{ - /// - /// Factory that will produce the . The default - /// implementation produces an engine that will run in-process. Implementations at - /// other layers can behave differently (for example, running the engine out-of-process). - /// - /// - /// This returns an No-op engine on non-Windows OS, because the backing storage depends on Windows APIs. - /// - internal static partial class SymbolSearchUpdateEngineFactory - { - public static async Task CreateEngineAsync( - Workspace workspace, - ISymbolSearchLogService logService, - CancellationToken cancellationToken) - { - var client = await RemoteHostClient.TryGetClientAsync(workspace, cancellationToken).ConfigureAwait(false); - if (client != null) - { - return new RemoteUpdateEngine(client, logService); - } - - // Couldn't go out of proc. Just do everything inside the current process. - return CreateEngineInProcess(); - } - - /// - /// This returns a No-op engine if called on non-Windows OS, because the backing storage depends on Windows APIs. - /// - public static ISymbolSearchUpdateEngine CreateEngineInProcess() - { - return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? new SymbolSearchUpdateEngine() - : new NoOpUpdateEngine(); - } - - private sealed class NoOpUpdateEngine : ISymbolSearchUpdateEngine - { - public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) - => ValueTaskFactory.FromResult(ImmutableArray.Empty); - - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - => ValueTaskFactory.FromResult(ImmutableArray.Empty); - - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - => ValueTaskFactory.FromResult(ImmutableArray.Empty); - - public ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, ISymbolSearchLogService logService, CancellationToken cancellationToken) - => default; - } - - private sealed class RemoteUpdateEngine : ISymbolSearchUpdateEngine - { - private readonly RemoteServiceConnection _connection; - - public RemoteUpdateEngine(RemoteHostClient client, ISymbolSearchLogService logService) - => _connection = client.CreateConnection(logService); - - public void Dispose() - => _connection.Dispose(); - - public async ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - { - var result = await _connection.TryInvokeAsync>( - (service, cancellationToken) => service.FindPackagesWithTypeAsync(source, name, arity, cancellationToken), - cancellationToken).ConfigureAwait(false); - - return result.HasValue ? result.Value : ImmutableArray.Empty; - } - - public async ValueTask> FindPackagesWithAssemblyAsync( - string source, string assemblyName, CancellationToken cancellationToken) - { - var result = await _connection.TryInvokeAsync>( - (service, cancellationToken) => service.FindPackagesWithAssemblyAsync(source, assemblyName, cancellationToken), - cancellationToken).ConfigureAwait(false); - - return result.HasValue ? result.Value : ImmutableArray.Empty; - } - - public async ValueTask> FindReferenceAssembliesWithTypeAsync( - string name, int arity, CancellationToken cancellationToken) - { - var result = await _connection.TryInvokeAsync>( - (service, cancellationToken) => service.FindReferenceAssembliesWithTypeAsync(name, arity, cancellationToken), - cancellationToken).ConfigureAwait(false); - - return result.HasValue ? result.Value : ImmutableArray.Empty; - } - - public async ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, ISymbolSearchLogService logService, CancellationToken cancellationToken) - { - // logService parameter is ignored since it's already set on the connection as a callback - _ = logService; - - _ = await _connection.TryInvokeAsync( - (service, callbackId, cancellationToken) => service.UpdateContinuouslyAsync(callbackId, sourceName, localSettingsDirectory, cancellationToken), - cancellationToken).ConfigureAwait(false); - } - } - } -} diff --git a/src/EditorFeatures/Core/Tagging/CompilationAvailableTaggerEventSource.cs b/src/EditorFeatures/Core/Tagging/CompilationAvailableTaggerEventSource.cs index 128f35fb8dee5..392bf5f4dd095 100644 --- a/src/EditorFeatures/Core/Tagging/CompilationAvailableTaggerEventSource.cs +++ b/src/EditorFeatures/Core/Tagging/CompilationAvailableTaggerEventSource.cs @@ -3,12 +3,12 @@ // See the LICENSE file in the project root for more information. using System; -using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Tagging; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Threading; @@ -16,7 +16,6 @@ namespace Microsoft.CodeAnalysis.Editor.Tagging { - /// /// Tagger event that fires once the compilation is available in the remote OOP process for a particular project. /// Used to trigger things such as: @@ -27,7 +26,7 @@ namespace Microsoft.CodeAnalysis.Editor.Tagging /// recomputation of inheritance margin items due to frozen-partial compilations being used. /// /// - internal class CompilationAvailableTaggerEventSource : ITaggerEventSource + internal sealed class CompilationAvailableTaggerEventSource : ITaggerEventSource { private readonly ITextBuffer _subjectBuffer; private readonly IAsynchronousOperationListener _asyncListener; @@ -114,7 +113,7 @@ private void OnEventSourceChanged(object? sender, TaggerEventArgs args) else { // if we can't get the client, just compute the compilation locally and fire the event once we have it. - await ComputeCompilationInCurrentProcessAsync(document.Project, cancellationToken).ConfigureAwait(false); + await CompilationAvailableHelpers.ComputeCompilationInCurrentProcessAsync(document.Project, cancellationToken).ConfigureAwait(false); } // now that we know we have an full compilation, retrigger the tagger so it can show accurate results with the @@ -123,9 +122,5 @@ private void OnEventSourceChanged(object? sender, TaggerEventArgs args) }, cancellationToken); task.CompletesAsyncOperation(token); } - - // this method is super basic. but it ensures that the remote impl and the local impl always agree. - public static Task ComputeCompilationInCurrentProcessAsync(Project project, CancellationToken cancellationToken) - => project.GetCompilationAsync(cancellationToken); } } diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf index b55de38bbb9d5..d78ba0c316f51 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf @@ -12,6 +12,11 @@ Aplikují se změny. + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration Změnit konfiguraci @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + Provést navrhovanou akci @@ -77,11 +82,6 @@ Získat nápovědu pro: {0} - - Get help for '{0}' from Bing - Získat nápovědu pro: {0} z Bingu - - Gathering Suggestions - '{0}' Shromažďují se návrhy – {0}. @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + Vložená diagnostika – Chyba Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + Vložená diagnostika – Hrubá úprava Inline Diagnostics - Warning - Inline Diagnostics - Warning + Vložená diagnostika – Upozornění @@ -152,6 +152,61 @@ Neplatné znaky v názvu sestavení + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control Klíčové slovo – Control @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + Inicializace {0} se nepodařila. Stav = {1}. Výjimka = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - Tento symbol nemá žádný základ. + Výsledky mohou být neúplné, protože řešení stále načítá projekty. @@ -547,11 +597,6 @@ Tento element nejde přejmenovat, protože se nachází v umístění, na které nejde přejít. - - '{0}' bases - Základy {0} - - {0} conflict(s) will be resolved Vyřeší se tento počet konfliktů: {0}. @@ -967,11 +1012,6 @@ Formátuje se aktuálně vybraný text... - - Cannot navigate to the symbol under the caret. - Nejde navigovat k symbolu pod stříškou. - - Go to Definition Přejít k definici @@ -1379,11 +1419,6 @@ Chcete pokračovat? Přejít na implementaci - - The symbol has no implementations. - Tento symbol nemá žádné implementace. - - New name: {0} Nový název: {0} @@ -1409,16 +1444,6 @@ Chcete pokračovat? Výpustka návrhu (…) - - '{0}' references - 'Reference symbolů {0} - - - - '{0}' implementations - 'Implementace symbolů {0} - - '{0}' declarations 'Deklarace symbolů {0} diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf index e926155e837aa..792feb55e79e9 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf @@ -12,6 +12,11 @@ Änderungen werden übernommen + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration Konfiguration ändern @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + Vorgeschlagene Aktion ausführen @@ -77,11 +82,6 @@ Hilfe zu "{0}" abrufen - - Get help for '{0}' from Bing - Hilfe zu "{0}" von Bing abrufen - - Gathering Suggestions - '{0}' Vorschläge werden gesammelt: "{0}" @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + Inline-Diagnose – Fehler Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + Inlinediagnose – NIcht unterstützte Bearbeitung Inline Diagnostics - Warning - Inline Diagnostics - Warning + Inline-Diagnose – Warnung @@ -152,6 +152,61 @@ Assemblyname enthält ungültige Zeichen. + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control Schlüsselwort – Steuerung @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + {0} konnte nicht initialisiert werden. Status = {1}. Ausnahme = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - Das Symbol verfügt über keine Basis. + Die Ergebnisse sind möglicherweise unvollständig, da die Projektmappe noch Projekte lädt. @@ -547,11 +597,6 @@ Dieses Element kann nicht umbenannt werden, weil es sich an einem Speicherort befindet, zu dem nicht navigiert werden kann. - - '{0}' bases - Basiswerte: "{0}" - - {0} conflict(s) will be resolved {0} Konflikt(e) werden gelöst @@ -967,11 +1012,6 @@ Aktuell markierter Text wird formatiert... - - Cannot navigate to the symbol under the caret. - Navigieren zu dem Symbol unter dem Caret nicht möglich. - - Go to Definition Gehe zu Definition @@ -1379,11 +1419,6 @@ Möchten Sie fortfahren? Zur Implementierung wechseln - - The symbol has no implementations. - Das Symbol verfügt über keine Implementierungen. - - New name: {0} Neuer Name: "{0}" @@ -1409,16 +1444,6 @@ Möchten Sie fortfahren? Auslassungspunkte für Vorschlag (…) - - '{0}' references - "{0}"-Verweise - - - - '{0}' implementations - "{0}"-Implementierungen - - '{0}' declarations "{0}"-Deklarationen diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf index 859fbe8d25002..22caeb5f0c87e 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf @@ -12,6 +12,11 @@ Aplicando cambios + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration Configuración de cambio @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + Ejecutar acción recomendada @@ -77,11 +82,6 @@ Obtener ayuda para "{0}" - - Get help for '{0}' from Bing - Obtener ayuda para "{0}" en Bing - - Gathering Suggestions - '{0}' Recopilando sugerencias: "{0}" @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + Diagnósticos integrados: error Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + Diagnósticos integrados: edición superficial Inline Diagnostics - Warning - Inline Diagnostics - Warning + Diagnóstico integrado: advertencia @@ -152,6 +152,61 @@ Caracteres no válidos en el nombre de ensamblado + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control Palabras clave: control @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + No se pudo inicializar {0}. Estado = {1}. Excepción = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - El símbolo no tiene base. + Los resultados pueden estar incompletos porque la solución aún está cargando proyectos. @@ -547,11 +597,6 @@ No se puede cambiar el nombre de este elemento porque está en una ubicación a la que no se puede navegar. - - '{0}' bases - Bases de "{0}" - - {0} conflict(s) will be resolved Se va(n) a resolver {0} conflicto(s) @@ -967,11 +1012,6 @@ Dando formato al texto seleccionado actualmente... - - Cannot navigate to the symbol under the caret. - No se puede navegar al símbolo que hay debajo del símbolo de intercalación. - - Go to Definition Ir a definición @@ -1379,11 +1419,6 @@ Do you want to proceed? Ir a implementación - - The symbol has no implementations. - El símbolo no tiene implementaciones. - - New name: {0} Nuevo nombre: {0} @@ -1409,16 +1444,6 @@ Do you want to proceed? Puntos suspensivos de sugerencia (…) - - '{0}' references - 'Referencias de "{0}" - - - - '{0}' implementations - 'Implementaciones de "{0}" - - '{0}' declarations 'Declaraciones de "{0}" diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf index d043127c5d95d..a92842642571f 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf @@ -12,6 +12,11 @@ Application des changements + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration Changer la configuration @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + Exécuter l'action suggérée @@ -77,11 +82,6 @@ Obtenir de l'aide pour '{0}' - - Get help for '{0}' from Bing - Obtenir de l'aide pour '{0}' à partir de Bing - - Gathering Suggestions - '{0}' Collecte des suggestions - '{0}' @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + Diagnostics en ligne – Erreur Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + Diagnostics en ligne – Modification grossière Inline Diagnostics - Warning - Inline Diagnostics - Warning + Diagnostics en ligne – Avertissement @@ -152,6 +152,61 @@ Caractères non valides dans le nom de l'assembly + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control Mot clé - contrôle @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + {0} n’a pas pu s’initialiser. État = {1}. Exception = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - Le symbole n'a pas de base. + Les résultats sont peut-être incomplets, car la solution est toujours en train de charger des projets. @@ -547,11 +597,6 @@ Vous ne pouvez pas renommer cet élément, car il se trouve dans un emplacement inaccessible. - - '{0}' bases - '{0}' bases - - {0} conflict(s) will be resolved {0} conflit(s) seront résolus @@ -967,11 +1012,6 @@ Mise en forme du texte actuellement sélectionné... - - Cannot navigate to the symbol under the caret. - Impossible de naviguer jusqu'au symbole sous le caret. - - Go to Definition Atteindre la définition @@ -1379,11 +1419,6 @@ Voulez-vous continuer ? Accéder à l'implémentation - - The symbol has no implementations. - Le symbole n'a pas d'implémentations. - - New name: {0} Nouveau nom : {0} @@ -1409,16 +1444,6 @@ Voulez-vous continuer ? Bouton de sélection (…) de suggestion - - '{0}' references - 'Références '{0}' - - - - '{0}' implementations - 'Implémentations '{0}' - - '{0}' declarations 'Déclarations '{0}' diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf index 1e6ea2c35ebc7..45efa478d4b68 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf @@ -12,6 +12,11 @@ Applicazione delle modifiche in corso + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration Cambia la configurazione @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + Esegui azione suggerita @@ -77,11 +82,6 @@ Visualizza la Guida per '{0}' - - Get help for '{0}' from Bing - Visualizza la Guida per '{0}' disponibile in Bing - - Gathering Suggestions - '{0}' Raccolta dei suggerimenti - '{0}' @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + Diagnostica inline - Errore Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + Diagnostica inline - Modifica non applicabile Inline Diagnostics - Warning - Inline Diagnostics - Warning + Diagnostica inline - Avviso @@ -152,6 +152,61 @@ Caratteri non validi nel nome dell'assembly + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control Parola chiave - Controllo @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + Non è stato possibile inizializzare {0}. Stato = {1}. Eccezione = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - Non è presente alcuna base per il simbolo. + I risultati potrebbero essere incompleti perché la soluzione ancora carica i progetti. @@ -547,11 +597,6 @@ Non è possibile rinominare questo elemento perché si trova in una posizione a cui non è possibile passare. - - '{0}' bases - Basi di '{0}' - - {0} conflict(s) will be resolved Verranno risolti {0} conflitti @@ -967,11 +1012,6 @@ Formattazione del testo attualmente selezionato... - - Cannot navigate to the symbol under the caret. - Non è possibile passare al simbolo sotto il punto di inserimento. - - Go to Definition Vai a definizione @@ -1379,11 +1419,6 @@ Continuare? Vai all'implementazione - - The symbol has no implementations. - Non sono presenti implementazioni per il simbolo. - - New name: {0} Nuovo nome: {0} @@ -1409,16 +1444,6 @@ Continuare? Puntini di sospensione di suggerimento (…) - - '{0}' references - 'Riferimenti di '{0}' - - - - '{0}' implementations - 'Implementazioni di '{0}' - - '{0}' declarations 'Dichiarazioni di '{0}' diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf index 4de85135e04b2..8ff3dd81f82cc 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf @@ -12,6 +12,11 @@ 変更の適用 + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration 構成の変更 @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + おすすめのアクションを実行する @@ -77,11 +82,6 @@ '{0}' のヘルプの表示 - - Get help for '{0}' from Bing - Bing から '{0}' のヘルプを表示します - - Gathering Suggestions - '{0}' 提案を収集しています - '{0}' @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + インライン診断 - エラー Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + インライン診断 - Rude Edit Inline Diagnostics - Warning - Inline Diagnostics - Warning + インライン診断 - 警告 @@ -152,6 +152,61 @@ アセンブリ名に無効な文字があります + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control キーワード - コントロール @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + {0} を初期化できませんでした。状態 = {1}。例外 = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - シンボルにベースがありません。 + ソリューションでプロジェクトを読み込み中であるため、結果は不完全になる可能性があります。 @@ -547,11 +597,6 @@ この要素は、移動できない場所にあるため、名前を変更できません。 - - '{0}' bases - '{0}' ベース - - {0} conflict(s) will be resolved {0} 個の競合が解決されます @@ -967,11 +1012,6 @@ 現在選択されているテキストを書式設定しています... - - Cannot navigate to the symbol under the caret. - カレットの下のシンボルに移動できません。 - - Go to Definition 定義へ移動 @@ -1379,11 +1419,6 @@ Do you want to proceed? 実装に移動 - - The symbol has no implementations. - シンボルに実装がありません。 - - New name: {0} 新しい名前: {0} @@ -1409,16 +1444,6 @@ Do you want to proceed? 提案事項の省略記号 (…) - - '{0}' references - '{0}' の参照 - - - - '{0}' implementations - '{0}' の実装 - - '{0}' declarations '{0}' の宣言 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf index 8d3ef95735b22..deef104085218 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf @@ -12,6 +12,11 @@ 변경 내용 적용 + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration 구성 변경 @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + 제안된 작업 실행 @@ -77,11 +82,6 @@ '{0}'에 대한 도움 받기 - - Get help for '{0}' from Bing - Bing에서 '{0}'에 대한 도움 받기 - - Gathering Suggestions - '{0}' 제안을 수집하는 중 - '{0}' @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + 인라인 진단 - 오류 Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + 인라인 진단 - Rude 편집 Inline Diagnostics - Warning - Inline Diagnostics - Warning + 인라인 진단 - 경고 @@ -152,6 +152,61 @@ 어셈블리 이름에 잘못된 문자가 있음 + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control 키워드 - 제어 @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + {0}을(를) 초기화하지 못했습니다. 상태 = {1}. 예외 = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - 기호에 베이스가 없습니다. + 솔루션이 아직 프로젝트를 로드하는 중이므로 결과가 불완전할 수 있습니다. @@ -547,11 +597,6 @@ 이 요소는 탐색할 수 없는 위치에 있으므로 이름을 바꿀 수 없습니다. - - '{0}' bases - '{0}' 기본 - - {0} conflict(s) will be resolved 충돌 {0}개가 해결됩니다. @@ -967,11 +1012,6 @@ 현재 선택한 텍스트의 서식을 지정하는 중... - - Cannot navigate to the symbol under the caret. - 캐럿에서 기호를 탐색할 수 없습니다. - - Go to Definition 정의로 이동 @@ -1379,11 +1419,6 @@ Do you want to proceed? 구현으로 이동 - - The symbol has no implementations. - 기호에 구현이 없습니다. - - New name: {0} 새 이름: {0} @@ -1409,16 +1444,6 @@ Do you want to proceed? 제안 줄임표(…) - - '{0}' references - '{0}' 참조 - - - - '{0}' implementations - '{0}' 구현 - - '{0}' declarations '{0}' 선언 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf index c0b02d84f796e..a1dbb17005f72 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf @@ -12,6 +12,11 @@ Stosowanie zmian + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration Zmień konfigurację @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + Wykonaj sugerowaną akcję @@ -77,11 +82,6 @@ Uzyskaj pomoc dla „{0}” - - Get help for '{0}' from Bing - Uzyskaj pomoc dla „{0}” z wyszukiwarki Bing - - Gathering Suggestions - '{0}' Zbieranie sugestii — „{0}” @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + Diagnostyka w tekście — błąd Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + Diagnostyka w tekście — edycja nagła Inline Diagnostics - Warning - Inline Diagnostics - Warning + Diagnostyka w tekście — ostrzeżenie @@ -152,6 +152,61 @@ Nieprawidłowe znaki w nazwie zestawu + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control Słowo kluczowe — kontrolka @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + Zainicjowanie języka {0} zakończyło się niepowodzeniem. Stan = {1}. Wyjątek = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - Symbol nie ma wartości podstawowej. + Wyniki mogą być niekompletne, ponieważ rozwiązanie nadal ładuje projekty. @@ -547,11 +597,6 @@ Nie możesz zmienić nazwy tego elementu, ponieważ znajduje się on w lokalizacji, do której nie można nawigować. - - '{0}' bases - Wartości podstawowe „{0}” - - {0} conflict(s) will be resolved Następująca liczba konfliktów zostanie rozwiązana: {0} @@ -967,11 +1012,6 @@ Trwa formatowanie aktualnie zaznaczonego tekstu... - - Cannot navigate to the symbol under the caret. - Nie można przejść do symbolu pod karetką. - - Go to Definition Przejdź do definicji @@ -1379,11 +1419,6 @@ Czy chcesz kontynuować? Przejdź do implementacji - - The symbol has no implementations. - Symbol nie ma implementacji. - - New name: {0} Nowa nazwa: {0} @@ -1409,16 +1444,6 @@ Czy chcesz kontynuować? Wielokropki sugestii (…) - - '{0}' references - 'Odwołania „{0}” - - - - '{0}' implementations - 'Implementacje „{0}” - - '{0}' declarations 'Deklaracje „{0}” diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf index ca25dc5627759..4d4bc9e938eaa 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf @@ -12,6 +12,11 @@ Aplicando mudanças + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration Alterar configuração @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + Executar a Ação Sugerida @@ -77,11 +82,6 @@ Obter ajuda para '{0}' - - Get help for '{0}' from Bing - Obter ajuda para o '{0}' do Bing - - Gathering Suggestions - '{0}' Obtendo Sugestões – '{0}' @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + Diagnóstico em linha - Erro Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + Diagnóstico em linha - Edição Rudimentar Inline Diagnostics - Warning - Inline Diagnostics - Warning + Diagnóstico em linha - Aviso @@ -152,6 +152,61 @@ Caracteres inválidos no nome do assembly + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control Palavra-chave – Controle @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + {0} falhou ao inicializar. Status = {1}. Exceção = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - O símbolo não tem nenhuma base. + Os resultados podem estar incompletos porque a solução ainda está carregando projetos. @@ -547,11 +597,6 @@ Você não pode renomear este elemento porque ele está em um local para o qual não é possível navegar. - - '{0}' bases - Bases '{0}' - - {0} conflict(s) will be resolved {0} conflito(s) será(ão) resolvido(s) @@ -967,11 +1012,6 @@ Formatando texto selecionado no momento... - - Cannot navigate to the symbol under the caret. - Não é possível navegar para o símbolo sob o cursor. - - Go to Definition Ir para Definição @@ -1379,11 +1419,6 @@ Deseja continuar? Ir Para Implementação - - The symbol has no implementations. - O símbolo não tem implementações. - - New name: {0} Novo nome: {0} @@ -1409,16 +1444,6 @@ Deseja continuar? Reticências de sugestão (…) - - '{0}' references - '{0}' referências - - - - '{0}' implementations - 'Implementações de '{0}' - - '{0}' declarations 'Declarações de '{0}' diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf index 8c401b366167b..d896d6adb11df 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf @@ -12,6 +12,11 @@ Применение изменений + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration Изменить конфигурацию @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + Выполнить предложенное действие @@ -77,11 +82,6 @@ Получить справку для "{0}" - - Get help for '{0}' from Bing - Получить справку для "{0}" из системы Bing - - Gathering Suggestions - '{0}' Сбор предложений — "{0}" @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + Встроенная диагностика — ошибка Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + Встроенная диагностика — грубое редактирование Inline Diagnostics - Warning - Inline Diagnostics - Warning + Встроенная диагностика — предупреждение @@ -152,6 +152,61 @@ Недопустимые символы в имени сборки + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control Ключевое слово — управление @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + Не удалось инициализировать {0}. Состояние = {1}. Исключение = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - У этого символа нет основания. + Результаты могут быть неполными, поскольку решение еще загружает проекты. @@ -547,11 +597,6 @@ Невозможно переименовать этот элемент, так как он находится в расположении, к которому невозможно перейти. - - '{0}' bases - Основания: "{0}" - - {0} conflict(s) will be resolved Конфликтов будет разрешено: {0} @@ -967,11 +1012,6 @@ Идет форматирование выбранного текста... - - Cannot navigate to the symbol under the caret. - Не удается перейти к символу, на котором находится курсор. - - Go to Definition Перейти к определению @@ -1379,11 +1419,6 @@ Do you want to proceed? Перейти к реализации - - The symbol has no implementations. - Этот символ не имеет реализации. - - New name: {0} Новое имя: {0} @@ -1409,16 +1444,6 @@ Do you want to proceed? Предложение с многоточием (…) - - '{0}' references - 'Ссылки "{0}" - - - - '{0}' implementations - 'Реализации "{0}" - - '{0}' declarations 'Объявления "{0}" diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf index e898ae599474d..cd8b7832b9156 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf @@ -12,6 +12,11 @@ Değişiklikler uygulanıyor + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration Değiştir yapılandırma @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + Önerilen Eylemi Yürüt @@ -77,11 +82,6 @@ '{0}' için yardım alın - - Get help for '{0}' from Bing - '{0}' için Bing'den yardım alın - - Gathering Suggestions - '{0}' Öneriler Toplanıyor - '{0}' @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + Satır İçi Tanılama - Hata Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + Satır İçi Tanılama - İşlenmemiş Düzenleme Inline Diagnostics - Warning - Inline Diagnostics - Warning + Satır İçi Tanılama - Uyarı @@ -152,6 +152,61 @@ Derleme adında geçersiz karakterler + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control Anahtar Sözcük - Denetim @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + {0} başlatılamadı. Durum = {1}. Özel durum = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - Sembolde taban yok. + Çözüm projeleri hala yüklemediğinden sonuçlar tamamlanmamış olabilir. @@ -547,11 +597,6 @@ Gezintiyle ulaşılamayan bir konumda bulunduğundan bu öğeyi yeniden adlandıramazsınız. - - '{0}' bases - '{0}' tabanları - - {0} conflict(s) will be resolved {0} çakışmaları çözümlenecek @@ -967,11 +1012,6 @@ Seçilen metin biçimlendiriliyor... - - Cannot navigate to the symbol under the caret. - Giriş işareti altında sembole gidilemiyor. - - Go to Definition Tanıma Git @@ -1379,11 +1419,6 @@ Devam etmek istiyor musunuz? Uygulamaya Git - - The symbol has no implementations. - Sembolde hiç uygulama yok. - - New name: {0} Yeni ad: {0} @@ -1409,16 +1444,6 @@ Devam etmek istiyor musunuz? Öneri üç noktası (…) - - '{0}' references - '{0}' başvuruları - - - - '{0}' implementations - '{0}' uygulamaları - - '{0}' declarations '{0}' bildirimleri diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf index 3733a9f97d464..c7686f6cf7967 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf @@ -12,6 +12,11 @@ 应用更改 + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration 更改配置 @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + 执行建议的操作 @@ -77,11 +82,6 @@ 获取有关“{0}”的帮助 - - Get help for '{0}' from Bing - 从必应获取有关“{0}”的帮助 - - Gathering Suggestions - '{0}' 正在收集建议 -“{0}” @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + 内联诊断 - 错误 Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + 内联诊断 - 原始编辑 Inline Diagnostics - Warning - Inline Diagnostics - Warning + 内联诊断 - 警告 @@ -152,6 +152,61 @@ 程序集名称中有无效字符 + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control 关键字-控制 @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + 无法初始化 {0}。状态 = {1}。异常 = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - 符号没有基数。 + 由于解决方案仍在加载项目,结果可能不完整。 @@ -547,11 +597,6 @@ 无法重命名此元素,因为它位于无法导航到的位置。 - - '{0}' bases - “{0}”基数 - - {0} conflict(s) will be resolved 将解决 {0} 个冲突 @@ -967,11 +1012,6 @@ 正在设置当前所选文本的格式... - - Cannot navigate to the symbol under the caret. - 无法导航到插入点下面的符号。 - - Go to Definition 转到定义 @@ -1379,11 +1419,6 @@ Do you want to proceed? 转到实现 - - The symbol has no implementations. - 符号没有实现。 - - New name: {0} 新名称: {0} @@ -1409,16 +1444,6 @@ Do you want to proceed? 建议使用省略号(…) - - '{0}' references - “{0}”引用 - - - - '{0}' implementations - “{0}”实现 - - '{0}' declarations “{0}”声明 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf index 74974444712cc..84fef01be95d5 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf @@ -12,6 +12,11 @@ 正在套用變更 + + Cannot navigate to the symbol under the caret. + Cannot navigate to the symbol under the caret. + + Change configuration 變更組態 @@ -44,7 +49,7 @@ Execute Suggested Action - Execute Suggested Action + 執行建議動作 @@ -77,11 +82,6 @@ 取得 '{0}' 的說明 - - Get help for '{0}' from Bing - 從 Bing 取得 '{0}' 的說明 - - Gathering Suggestions - '{0}' 正在蒐集建議 - '{0}' @@ -119,17 +119,17 @@ Inline Diagnostics - Error - Inline Diagnostics - Error + 內嵌診斷 - 錯誤 Inline Diagnostics - Rude Edit - Inline Diagnostics - Rude Edit + 內嵌診斷 - 粗略編輯 Inline Diagnostics - Warning - Inline Diagnostics - Warning + 內嵌診斷 - 警告 @@ -152,6 +152,61 @@ 組件名稱包含無效的字元 + + JSON in string literal - Array + JSON in string literal - Array + + + + JSON in string literal - Comment + JSON in string literal - Comment + + + + JSON in string literal - Constructor Name + JSON in string literal - Constructor Name + + + + JSON in string literal - Keyword + JSON in string literal - Keyword + + + + JSON in string literal - Number + JSON in string literal - Number + + + + JSON in string literal - Object + JSON in string literal - Object + + + + JSON in string literal - Operator + JSON in string literal - Operator + + + + JSON in string literal - Property Name + JSON in string literal - Property Name + + + + JSON in string literal - Punctuation + JSON in string literal - Punctuation + + + + JSON in string literal - String + JSON in string literal - String + + + + JSON in string literal - Text + JSON in string literal - Text + + Keyword - Control 關鍵字 - 控制項 @@ -159,7 +214,7 @@ {0} failed to initialize. Status = {1}. Exception = {2} - {0} failed to initialize. Status = {1}. Exception = {2} + {0} 無法初始化。狀態 = {1}。例外狀況 = {2} {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. @@ -269,12 +324,7 @@ The results may be incomplete due to the solution still loading projects. - The results may be incomplete due to the solution still loading projects. - - - - The symbol has no base. - 該符號沒有任何基底。 + 結果可能不完整,因為方案仍在載入專案。 @@ -547,11 +597,6 @@ 因為無法瀏覽到此項目的所在位置,所以無法予以重新命名。 - - '{0}' bases - '{0}' 個基底 - - {0} conflict(s) will be resolved 將解決 {0} 項衝突 @@ -967,11 +1012,6 @@ 正在格式化目前選取的文字... - - Cannot navigate to the symbol under the caret. - 無法巡覽至插入號下的符號。 - - Go to Definition 移至定義 @@ -1379,11 +1419,6 @@ Do you want to proceed? 前往實作 - - The symbol has no implementations. - 符號沒有任何實作。 - - New name: {0} 新名稱: {0} @@ -1409,16 +1444,6 @@ Do you want to proceed? 建議省略符號 (…) - - '{0}' references - '{0}' 參考 - - - - '{0}' implementations - '{0}' 實作 - - '{0}' declarations '{0}' 宣告 diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index 255c1149b57f6..aa218035e8803 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs @@ -47,6 +47,7 @@ public abstract partial class AbstractCodeActionOrUserDiagnosticTest { public struct TestParameters { + internal readonly CodeActionOptions codeActionOptions; internal readonly OptionsCollection options; internal readonly TestHost testHost; internal readonly string workspaceKind; @@ -63,6 +64,7 @@ internal TestParameters( ParseOptions parseOptions = null, CompilationOptions compilationOptions = null, OptionsCollection options = null, + CodeActionOptions? codeActionOptions = null, object fixProviderData = null, int index = 0, CodeActionPriority? priority = null, @@ -75,6 +77,7 @@ internal TestParameters( this.parseOptions = parseOptions; this.compilationOptions = compilationOptions; this.options = options; + this.codeActionOptions = codeActionOptions ?? CodeActionOptions.Default; this.fixProviderData = fixProviderData; this.index = index; this.priority = priority; @@ -86,28 +89,31 @@ internal TestParameters( } public TestParameters WithParseOptions(ParseOptions parseOptions) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithCompilationOptions(CompilationOptions compilationOptions) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); internal TestParameters WithOptions(OptionsCollection options) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + + internal TestParameters WithCodeActionOptions(CodeActionOptions codeActionOptions) + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithFixProviderData(object fixProviderData) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithIndex(int index) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithRetainNonFixableDiagnostics(bool retainNonFixableDiagnostics) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithIncludeDiagnosticsOutsideSelection(bool includeDiagnosticsOutsideSelection) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithWorkspaceKind(string workspaceKind) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); } #pragma warning disable IDE0052 // Remove unread private members (unused when CODE_STYLE is set) @@ -341,15 +347,13 @@ protected async Task TestExactActionSetOfferedAsync( IEnumerable expectedActionSet, TestParameters parameters = default) { - using (var workspace = CreateWorkspaceFromOptions(initialMarkup, parameters)) - { - var (actions, _) = await GetCodeActionsAsync(workspace, parameters); + using var workspace = CreateWorkspaceFromOptions(initialMarkup, parameters); + var (actions, _) = await GetCodeActionsAsync(workspace, parameters); - var actualActionSet = actions.Select(a => a.Title); - Assert.True(actualActionSet.SequenceEqual(expectedActionSet), - "Expected: " + string.Join(", ", expectedActionSet) + - "\nActual: " + string.Join(", ", actualActionSet)); - } + var actualActionSet = actions.Select(a => a.Title); + Assert.True(actualActionSet.SequenceEqual(expectedActionSet), + "Expected: " + string.Join(", ", expectedActionSet) + + "\nActual: " + string.Join(", ", actualActionSet)); } protected async Task TestActionCountAsync( @@ -379,7 +383,7 @@ internal Task TestInRegularAndScriptAsync( { return TestInRegularAndScript1Async( initialMarkup, expectedMarkup, index, - new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, title: title, testHost: testHost)); + new TestParameters(parseOptions, compilationOptions, options, CodeActionOptions.Default, fixProviderData, index, priority, title: title, testHost: testHost)); } internal Task TestInRegularAndScript1Async( @@ -419,7 +423,7 @@ internal Task TestAsync( return TestAsync( initialMarkup, expectedMarkup, - new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, testHost: testHost)); + new TestParameters(parseOptions, compilationOptions, options, CodeActionOptions.Default, fixProviderData, index, priority, testHost: testHost)); } private async Task TestAsync( diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs index aed04f6f96b5b..31ac98f267b19 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs @@ -69,7 +69,8 @@ private static async Task GetCodeRefactoringAsync( var span = documentsWithSelections.Single().SelectedSpans.Single(); var actions = ArrayBuilder<(CodeAction, TextSpan?)>.GetInstance(); var document = workspace.CurrentSolution.GetDocument(documentsWithSelections.Single().Id); - var context = new CodeRefactoringContext(document, span, (a, t) => actions.Add((a, t)), isBlocking: false, CancellationToken.None); + var options = CodeActionOptions.Default; + var context = new CodeRefactoringContext(document, span, (a, t) => actions.Add((a, t)), options, CancellationToken.None); await provider.ComputeRefactoringsAsync(context); var result = actions.Count > 0 ? new CodeRefactoring(provider, actions.ToImmutable()) : null; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs index ccdb7364ed8fc..b0932a2a27dac 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs @@ -111,19 +111,30 @@ public void TestSupportedDiagnosticsMessageDescription() } } - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/26717")] + [Fact] public void TestSupportedDiagnosticsMessageHelpLinkUri() { using (var workspace = new AdhocWorkspace()) { var diagnosticAnalyzer = CreateDiagnosticProviderAndFixer(workspace).Item1; if (diagnosticAnalyzer == null) - { return; - } foreach (var descriptor in diagnosticAnalyzer.SupportedDiagnostics) { + // These don't come up in UI. + if (descriptor.DefaultSeverity == DiagnosticSeverity.Hidden && descriptor.CustomTags.Contains(WellKnownDiagnosticTags.NotConfigurable)) + continue; + + if (descriptor.Id is "RE0001" or "JSON001" or "JSON002") // Currently not documented. https://github.com/dotnet/roslyn/issues/48530 + continue; + + if (descriptor.Id == "IDE0043") // Intentionally undocumented. It will be removed in favor of CA2241 + continue; + + if (descriptor.Id == "IDE1007") + continue; + Assert.NotEqual("", descriptor.HelpLinkUri ?? ""); } } @@ -166,7 +177,7 @@ internal override async Task> GetDiagnosticsAsync( var ids = new HashSet(fixer.FixableDiagnosticIds); var dxs = diagnostics.Where(d => ids.Contains(d.Id)).ToList(); var (resultDiagnostics, codeActions, actionToInvoke) = await GetDiagnosticAndFixesAsync( - dxs, fixer, testDriver, document, span, annotation, parameters.index); + dxs, fixer, testDriver, document, span, parameters.codeActionOptions, annotation, parameters.index); // If we are also testing non-fixable diagnostics, // then the result diagnostics need to include all diagnostics, diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs index 3809f0ddb1021..153893ffa064d 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs @@ -98,7 +98,7 @@ internal override async Task> GetDiagnosticsAsync( var wrapperCodeFixer = new WrapperCodeFixProvider(fixer, filteredDiagnostics.Select(d => d.Id)); return await GetDiagnosticAndFixesAsync( filteredDiagnostics, wrapperCodeFixer, testDriver, document, - span, annotation, parameters.index); + span, CodeActionOptions.Default, annotation, parameters.index); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs index 815643c37d0a3..dde2727fe3d0c 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs @@ -63,7 +63,7 @@ internal override async Task> GetDiagnosticsAsync( return await GetDiagnosticAndFixesAsync( diagnostics, CodeFixProvider, testDriver, document, - span, annotation, parameters.index); + span, CodeActionOptions.Default, annotation, parameters.index); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs index e658351e39cc3..4a5445c0d774d 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs @@ -172,6 +172,7 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o TestDiagnosticAnalyzerDriver testDriver, Document document, TextSpan span, + CodeActionOptions options, string annotation, int index) { @@ -181,20 +182,6 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o } var scope = GetFixAllScope(annotation); - return await GetDiagnosticAndFixesAsync( - diagnostics, fixer, testDriver, document, span, scope, index); - } - - private async Task<(ImmutableArray, ImmutableArray, CodeAction actionToinvoke)> GetDiagnosticAndFixesAsync( - IEnumerable diagnostics, - CodeFixProvider fixer, - TestDiagnosticAnalyzerDriver testDriver, - Document document, - TextSpan span, - FixAllScope? scope, - int index) - { - Assert.NotEmpty(diagnostics); var intersectingDiagnostics = diagnostics.Where(d => d.Location.SourceSpan.IntersectsWith(span)) .ToImmutableArray(); @@ -204,8 +191,11 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o foreach (var diagnostic in intersectingDiagnostics) { var context = new CodeFixContext( - document, diagnostic, + document, + diagnostic.Location.SourceSpan, + ImmutableArray.Create(diagnostic), (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), + options, CancellationToken.None); await fixer.RegisterCodeFixesAsync(context); @@ -213,34 +203,29 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o VerifyCodeActionsRegisteredByProvider(fixer, fixes); - var actions = fixes.SelectAsArray(f => f.Action); - - actions = MassageActions(actions); + var actions = MassageActions(fixes.SelectAsArray(f => f.Action)); if (scope == null) { // Simple code fix. return (intersectingDiagnostics, actions, actions.Length == 0 ? null : actions[index]); } - else - { - var equivalenceKey = actions[index].EquivalenceKey; + var equivalenceKey = actions[index].EquivalenceKey; - // Fix all fix. - var fixAllProvider = fixer.GetFixAllProvider(); - Assert.NotNull(fixAllProvider); + // Fix all fix. + var fixAllProvider = fixer.GetFixAllProvider(); + Assert.NotNull(fixAllProvider); - var fixAllState = GetFixAllState( - fixAllProvider, diagnostics, fixer, testDriver, document, - scope.Value, equivalenceKey); - var fixAllContext = new FixAllContext(fixAllState, new ProgressTracker(), CancellationToken.None); - var fixAllFix = await fixAllProvider.GetFixAsync(fixAllContext); + var fixAllState = GetFixAllState( + fixAllProvider, diagnostics, fixer, testDriver, document, + scope.Value, equivalenceKey); + var fixAllContext = new FixAllContext(fixAllState, new ProgressTracker(), CancellationToken.None); + var fixAllFix = await fixAllProvider.GetFixAsync(fixAllContext); - // We have collapsed the fixes down to the single fix-all fix, so we just let our - // caller know they should pull that entry out of the result. - return (intersectingDiagnostics, ImmutableArray.Create(fixAllFix), fixAllFix); - } + // We have collapsed the fixes down to the single fix-all fix, so we just let our + // caller know they should pull that entry out of the result. + return (intersectingDiagnostics, ImmutableArray.Create(fixAllFix), fixAllFix); } private static FixAllState GetFixAllState( @@ -280,7 +265,7 @@ private protected Task TestActionCountInAllFixesAsync( { return TestActionCountInAllFixesAsync( initialMarkup, - new TestParameters(parseOptions, compilationOptions, options, fixProviderData), + new TestParameters(parseOptions, compilationOptions, options, CodeActionOptions.Default, fixProviderData), count); } diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs index e3642b0df912a..0f0f4f1a4e01b 100644 --- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs +++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs @@ -87,7 +87,9 @@ public async Task TestGetFixesAsyncWithDuplicateDiagnostics() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify that we do not crash when computing fixes. - _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None); + var options = CodeActionOptions.Default; + + _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); // Verify that code fix is invoked with both the diagnostics in the context, // i.e. duplicate diagnostics are not silently discarded by the CodeFixService. @@ -113,7 +115,8 @@ public async Task TestGetFixesAsyncHasNoDuplicateConfigurationActions() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify registered configuration code actions do not have duplicates. - var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None); + var options = CodeActionOptions.Default; + var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); var codeActions = fixCollections.SelectMany(c => c.Fixes.Select(f => f.Action)).ToImmutableArray(); Assert.Equal(7, codeActions.Length); var uniqueTitles = new HashSet(); @@ -143,16 +146,18 @@ public async Task TestGetFixesAsyncForFixableAndNonFixableAnalyzersAsync() using var workspace = tuple.workspace; GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); + var options = CodeActionOptions.Default; + // Verify only analyzerWithFix is executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Normal, isBlocking: false, + priority: CodeActionRequestPriority.Normal, options, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.False(analyzerWithoutFix.ReceivedCallback); // Verify both analyzerWithFix and analyzerWithoutFix are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Lowest'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Lowest, isBlocking: false, + priority: CodeActionRequestPriority.Lowest, options, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.True(analyzerWithoutFix.ReceivedCallback); @@ -180,8 +185,10 @@ public async Task TestGetFixesAsyncForDocumentDiagnosticAnalyzerAsync() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify both analyzers are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. + var options = CodeActionOptions.Default; + _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Normal, isBlocking: false, + priority: CodeActionRequestPriority.Normal, options, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(documentDiagnosticAnalyzer.ReceivedCallback); } @@ -265,7 +272,8 @@ private static async Task> GetAddedFixesAsync( var reference = new MockAnalyzerReference(codefix, ImmutableArray.Create(diagnosticAnalyzer)); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); document = project.Documents.Single(); - var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None); + var options = CodeActionOptions.Default; + var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); if (exception) { @@ -679,7 +687,9 @@ private static async Task> GetNuGetAndVsixCode var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); - return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None); + var options = CodeActionOptions.Default; + + return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); } private sealed class NuGetCodeFixProvider : AbstractNuGetOrVsixCodeFixProvider diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs index c569be4d95dcd..e7706f9195b6b 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs @@ -123,7 +123,7 @@ public async Task AddConstructorWithoutBody() public C(); }"; await TestAddConstructorAsync(input, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -365,7 +365,7 @@ public async Task AddEvent() public event System.Action E; }"; await TestAddEventAsync(input, expected, - codeGenerationOptions: new CodeGenerationOptions(addImports: false)); + context: new CodeGenerationContext(addImports: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -400,8 +400,8 @@ event EventHandler Click } } }"; - var options = new CodeGenerationOptions(reuseSyntax: true); - await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, codeGenerationOptions: options); + var context = new CodeGenerationContext(reuseSyntax: true); + await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, context: context); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -414,7 +414,7 @@ public async Task AddUnsafeEvent() }"; await TestAddEventAsync(input, expected, modifiers: new Editing.DeclarationModifiers(isUnsafe: true), - codeGenerationOptions: new CodeGenerationOptions(addImports: false)); + context: new CodeGenerationContext(addImports: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -437,7 +437,7 @@ public event System.Action E await TestAddEventAsync(input, expected, addMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol(ImmutableArray.Empty, Accessibility.NotApplicable, ImmutableArray.Empty), removeMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol(ImmutableArray.Empty, Accessibility.NotApplicable, ImmutableArray.Empty), - codeGenerationOptions: new CodeGenerationOptions(addImports: false)); + context: new CodeGenerationContext(addImports: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -472,8 +472,8 @@ public int FInt() return 0; } }"; - var options = new CodeGenerationOptions(reuseSyntax: true); - await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, codeGenerationOptions: options); + var context = new CodeGenerationContext(reuseSyntax: true); + await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, context: context); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -551,7 +551,7 @@ public async Task AddMethodWithoutBody() }"; await TestAddMethodAsync(input, expected, returnType: typeof(int), - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -1003,8 +1003,8 @@ public int P } } }"; - var options = new CodeGenerationOptions(reuseSyntax: true); - await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, codeGenerationOptions: options); + var context = new CodeGenerationContext(reuseSyntax: true); + await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, context: context); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -1016,8 +1016,7 @@ await TestAddPropertyAsync(input, expected, type: typeof(string), parameters: Parameters(Parameter(typeof(int), "i")), getStatements: "return String.Empty;", - isIndexer: true, - codeGenerationOptions: new CodeGenerationOptions(parseOptions: CSharpParseOptions.Default)); + isIndexer: true); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -1538,7 +1537,7 @@ public class C }"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, forceLanguage: LanguageNames.CSharp, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); } } @@ -1557,7 +1556,7 @@ public static void ExtMethod1(this string s, int y, string z) {} public static void ExtMethod1(this string s, int y, string z); }"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false), + context: new CodeGenerationContext(generateMethodBodies: false), onlyGenerateMembers: true); } @@ -1589,7 +1588,7 @@ public class C } }"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); } [WorkItem(812738, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/812738")] @@ -1607,7 +1606,7 @@ End Sub public void Goo(int x, ref int y, ref object z); }"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false), + context: new CodeGenerationContext(generateMethodBodies: false), onlyGenerateMembers: true); } @@ -1642,7 +1641,7 @@ public delegate void D(T t, U u) } }"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false), + context: new CodeGenerationContext(generateMethodBodies: false), onlyGenerateMembers: true); } } diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.Shared.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.Shared.cs index 40cbb9df11e6a..6dd04f223f12f 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.Shared.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.Shared.cs @@ -343,7 +343,7 @@ private class CAccessA } }"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false), + context: new CodeGenerationContext(generateMethodBodies: false), forceLanguage: LanguageNames.CSharp); initial = "Namespace [|N|] \n End Namespace"; @@ -510,7 +510,7 @@ Private Delegate Sub DAccessA() End Class End Namespace"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false), + context: new CodeGenerationContext(generateMethodBodies: false), forceLanguage: LanguageNames.VisualBasic); } @@ -562,7 +562,7 @@ Private B As String [Fact, Trait(Traits.Feature, Traits.Features.CodeGenerationSortDeclarations)] public async Task TestDefaultTypeMemberAccessibility2() { - var codeGenOptionNoBody = new CodeGenerationOptions(generateMethodBodies: false); + var codeGenOptionNoBody = new CodeGenerationContext(generateMethodBodies: false); var generationSource = "public class [|C|] { private void B(){} public void C(){} }"; var initial = "public interface [|I|] { void A(); }"; @@ -570,7 +570,7 @@ public async Task TestDefaultTypeMemberAccessibility2() void B(); void C(); }"; - await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true, codeGenerationOptions: codeGenOptionNoBody); + await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true, context: codeGenOptionNoBody); initial = "Public Interface [|I|] \n Sub A() \n End Interface"; expected = @"Public Interface I @@ -578,7 +578,7 @@ Sub A() Sub B() Sub C() End Interface"; - await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true, codeGenerationOptions: codeGenOptionNoBody); + await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true, context: codeGenOptionNoBody); initial = "Public Class [|C|] \n Sub A() \n End Sub \n End Class"; expected = @"Public Class C @@ -670,7 +670,7 @@ public C() { } public C(); }"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false, generateDocumentationComments: true), + context: new CodeGenerationContext(generateMethodBodies: false, generateDocumentationComments: true), onlyGenerateMembers: true); } @@ -718,7 +718,7 @@ public class C } }"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); var initialVB = "Namespace [|N|] End Namespace"; var expectedVB = @"Namespace N End NamespaceNamespace N @@ -735,7 +735,7 @@ Public NotOverridable Overrides Sub Method1() End Class End Namespace"; await TestGenerateFromSourceSymbolAsync(generationSource, initialVB, expectedVB, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); } } } diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.VisualBasic.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.VisualBasic.cs index 0f4ae26c5ed3d..33169949eae08 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.VisualBasic.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.VisualBasic.cs @@ -117,7 +117,7 @@ public async Task AddConstructorWithoutBody() Public Sub New() End Class"; await TestAddConstructorAsync(input, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -355,7 +355,7 @@ Class C Public Event E As Action End Class"; await TestAddEventAsync(input, expected, - codeGenerationOptions: new CodeGenerationOptions(addImports: false)); + context: new CodeGenerationContext(addImports: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -388,8 +388,8 @@ End RemoveHandler End RaiseEvent End Event End Class"; - var options = new CodeGenerationOptions(reuseSyntax: true); - await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, codeGenerationOptions: options); + var context = new CodeGenerationContext(reuseSyntax: true); + await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, context: context); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -425,7 +425,7 @@ await TestAddEventAsync(input, expected, ImmutableArray.Empty, Accessibility.NotApplicable, ImmutableArray.Empty), getExplicitInterfaceImplementations: GetExplicitInterfaceEvent, type: typeof(System.ComponentModel.PropertyChangedEventHandler), - codeGenerationOptions: new CodeGenerationOptions(addImports: false)); + context: new CodeGenerationContext(addImports: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -447,7 +447,7 @@ End Event End Class"; await TestAddEventAsync(input, expected, addMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol(ImmutableArray.Empty, Accessibility.NotApplicable, ImmutableArray.Empty), - codeGenerationOptions: new CodeGenerationOptions(addImports: false)); + context: new CodeGenerationContext(addImports: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -480,7 +480,7 @@ await TestAddEventAsync(input, expected, ImmutableArray.Empty, Accessibility.NotApplicable, removeStatements), raiseMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol( ImmutableArray.Empty, Accessibility.NotApplicable, raiseStatements), - codeGenerationOptions: new CodeGenerationOptions(addImports: false)); + context: new CodeGenerationContext(addImports: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -509,8 +509,8 @@ Public Function FInt() As Integer Return 0 End Function End Class"; - var options = new CodeGenerationOptions(reuseSyntax: true); - await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, codeGenerationOptions: options); + var context = new CodeGenerationContext(reuseSyntax: true); + await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, context: context); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -577,7 +577,7 @@ Public Sub M() End Class"; await TestAddMethodAsync(input, expected, returnType: typeof(void), - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -1035,8 +1035,8 @@ Return 0 End Get End Property End Class"; - var options = new CodeGenerationOptions(reuseSyntax: true); - await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, codeGenerationOptions: options); + var context = new CodeGenerationContext(reuseSyntax: true); + await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, context: context); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -1050,7 +1050,7 @@ await TestAddPropertyAsync(input, expected, type: typeof(int), getStatements: "Return 0", setStatements: "Me.P = Value", - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] @@ -1677,7 +1677,7 @@ End Class End Namespace"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, forceLanguage: LanguageNames.VisualBasic, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false)); + context: new CodeGenerationContext(generateMethodBodies: false)); } [WorkItem(848357, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/848357")] @@ -1701,7 +1701,7 @@ Public Delegate Sub D(Of T1 As Structure, T2 As Class)(t As T1, u As T2) End Class End Namespace"; await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, - codeGenerationOptions: new CodeGenerationOptions(generateMethodBodies: false), + context: new CodeGenerationContext(generateMethodBodies: false), onlyGenerateMembers: true); } } diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs index 4941a5b65e3a3..d5d81a09d7eb8 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; @@ -15,6 +16,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -35,11 +37,11 @@ internal static async Task TestAddNamespaceAsync( string name = "N", IList imports = null, IList members = null, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { - using var context = await TestContext.CreateAsync(initial, expected); + using var testContext = await TestContext.CreateAsync(initial, expected); var @namespace = CodeGenerationSymbolFactory.CreateNamespaceSymbol(name, imports, members); - context.Result = await context.Service.AddNamespaceAsync(context.Solution, (INamespaceSymbol)context.GetDestination(), @namespace, codeGenerationOptions); + testContext.Result = await testContext.Service.AddNamespaceAsync(testContext.Solution, (INamespaceSymbol)testContext.GetDestination(), @namespace, context ?? CodeGenerationContext.Default, CancellationToken.None); } internal static async Task TestAddFieldAsync( @@ -49,13 +51,13 @@ internal static async Task TestAddFieldAsync( string name = "F", Accessibility accessibility = Accessibility.Public, Editing.DeclarationModifiers modifiers = default, - CodeGenerationOptions codeGenerationOptions = null, + CodeGenerationContext context = null, bool hasConstantValue = false, object constantValue = null, bool addToCompilationUnit = false) { - using var context = await TestContext.CreateAsync(initial, expected); - var typeSymbol = type != null ? type(context.SemanticModel) : null; + using var testContext = await TestContext.CreateAsync(initial, expected); + var typeSymbol = type != null ? type(testContext.SemanticModel) : null; var field = CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: default, accessibility, @@ -64,14 +66,16 @@ internal static async Task TestAddFieldAsync( name, hasConstantValue, constantValue); + if (!addToCompilationUnit) { - context.Result = await context.Service.AddFieldAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), field, codeGenerationOptions); + testContext.Result = await testContext.Service.AddFieldAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), field, context ?? CodeGenerationContext.Default, CancellationToken.None); } else { - var newRoot = context.Service.AddField(await context.Document.GetSyntaxRootAsync(), field, codeGenerationOptions); - context.Result = context.Document.WithSyntaxRoot(newRoot); + var options = await CodeGenerationOptions.FromDocumentAsync(context ?? CodeGenerationContext.Default, testContext.Document, CancellationToken.None); + var newRoot = testContext.Service.AddField(await testContext.Document.GetSyntaxRootAsync(), field, options, CancellationToken.None); + testContext.Result = testContext.Document.WithSyntaxRoot(newRoot); } } @@ -85,10 +89,10 @@ internal static async Task TestAddConstructorAsync( ImmutableArray statements = default, ImmutableArray baseArguments = default, ImmutableArray thisArguments = default, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { - using var context = await TestContext.CreateAsync(initial, expected); - var parameterSymbols = GetParameterSymbols(parameters, context); + using var testContext = await TestContext.CreateAsync(initial, expected); + var parameterSymbols = GetParameterSymbols(parameters, testContext); var ctor = CodeGenerationSymbolFactory.CreateConstructorSymbol( attributes: default, accessibility, @@ -98,7 +102,8 @@ internal static async Task TestAddConstructorAsync( statements, baseConstructorArguments: baseArguments, thisConstructorArguments: thisArguments); - context.Result = await context.Service.AddMethodAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), ctor, codeGenerationOptions); + + testContext.Result = await testContext.Service.AddMethodAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), ctor, context ?? CodeGenerationContext.Default, CancellationToken.None); } internal static async Task TestAddMethodAsync( @@ -113,22 +118,22 @@ internal static async Task TestAddMethodAsync( ImmutableArray> parameters = default, string statements = null, ImmutableArray handlesExpressions = default, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { if (statements != null) { expected = expected.Replace("$$", statements); } - using var context = await TestContext.CreateAsync(initial, expected); - var parameterSymbols = GetParameterSymbols(parameters, context); - var parsedStatements = context.ParseStatements(statements); - var explicitInterfaceImplementations = GetMethodSymbols(getExplicitInterfaces, context); + using var testContext = await TestContext.CreateAsync(initial, expected); + var parameterSymbols = GetParameterSymbols(parameters, testContext); + var parsedStatements = testContext.ParseStatements(statements); + var explicitInterfaceImplementations = GetMethodSymbols(getExplicitInterfaces, testContext); var method = CodeGenerationSymbolFactory.CreateMethodSymbol( attributes: default, accessibility, modifiers, - GetTypeSymbol(returnType)(context.SemanticModel), + GetTypeSymbol(returnType)(testContext.SemanticModel), RefKind.None, explicitInterfaceImplementations, name, @@ -136,7 +141,8 @@ internal static async Task TestAddMethodAsync( parameterSymbols, parsedStatements, handlesExpressions: handlesExpressions); - context.Result = await context.Service.AddMethodAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), method, codeGenerationOptions); + + testContext.Result = await testContext.Service.AddMethodAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), method, context ?? CodeGenerationContext.Default, CancellationToken.None); } internal static async Task TestAddOperatorsAsync( @@ -148,7 +154,7 @@ internal static async Task TestAddOperatorsAsync( Type returnType = null, ImmutableArray> parameters = default, string statements = null, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { if (statements != null) { @@ -158,20 +164,20 @@ internal static async Task TestAddOperatorsAsync( } } - using var context = await TestContext.CreateAsync(initial, expected); - var parameterSymbols = GetParameterSymbols(parameters, context); - var parsedStatements = context.ParseStatements(statements); + using var testContext = await TestContext.CreateAsync(initial, expected); + var parameterSymbols = GetParameterSymbols(parameters, testContext); + var parsedStatements = testContext.ParseStatements(statements); var methods = operatorKinds.Select(kind => CodeGenerationSymbolFactory.CreateOperatorSymbol( attributes: default, accessibility, modifiers, - GetTypeSymbol(returnType)(context.SemanticModel), + GetTypeSymbol(returnType)(testContext.SemanticModel), kind, parameterSymbols, parsedStatements)); - context.Result = await context.Service.AddMembersAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), methods.ToArray(), codeGenerationOptions); + testContext.Result = await testContext.Service.AddMembersAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), methods.ToArray(), context ?? CodeGenerationContext.Default, CancellationToken.None); } internal static async Task TestAddUnsupportedOperatorAsync( @@ -182,17 +188,17 @@ internal static async Task TestAddUnsupportedOperatorAsync( Type returnType = null, ImmutableArray> parameters = default, string statements = null, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { - using var context = await TestContext.CreateAsync(initial, initial, ignoreResult: true); - var parameterSymbols = GetParameterSymbols(parameters, context); - var parsedStatements = context.ParseStatements(statements); + using var testContext = await TestContext.CreateAsync(initial, initial, ignoreResult: true); + var parameterSymbols = GetParameterSymbols(parameters, testContext); + var parsedStatements = testContext.ParseStatements(statements); var method = CodeGenerationSymbolFactory.CreateOperatorSymbol( attributes: default, accessibility, modifiers, - GetTypeSymbol(returnType)(context.SemanticModel), + GetTypeSymbol(returnType)(testContext.SemanticModel), operatorKind, parameterSymbols, parsedStatements); @@ -200,7 +206,7 @@ internal static async Task TestAddUnsupportedOperatorAsync( ArgumentException exception = null; try { - await context.Service.AddMethodAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), method, codeGenerationOptions); + await testContext.Service.AddMethodAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), method, context ?? CodeGenerationContext.Default, CancellationToken.None); } catch (ArgumentException e) { @@ -221,57 +227,60 @@ internal static async Task TestAddConversionAsync( Accessibility accessibility = Accessibility.Public, Editing.DeclarationModifiers modifiers = default, string statements = null, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { if (statements != null) { expected = expected.Replace("$$", statements); } - using var context = await TestContext.CreateAsync(initial, expected); - var parsedStatements = context.ParseStatements(statements); + using var testContext = await TestContext.CreateAsync(initial, expected); + var parsedStatements = testContext.ParseStatements(statements); var method = CodeGenerationSymbolFactory.CreateConversionSymbol( attributes: default, accessibility, modifiers, - GetTypeSymbol(toType)(context.SemanticModel), - fromType(context.SemanticModel), + GetTypeSymbol(toType)(testContext.SemanticModel), + fromType(testContext.SemanticModel), containingType: null, isImplicit, parsedStatements); - context.Result = await context.Service.AddMethodAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), method, codeGenerationOptions); + testContext.Result = await testContext.Service.AddMethodAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), method, context ?? CodeGenerationContext.Default, CancellationToken.None); } internal static async Task TestAddStatementsAsync( string initial, string expected, string statements, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { if (statements != null) { expected = expected.Replace("$$", statements); } - using var context = await TestContext.CreateAsync(initial, expected); - var parsedStatements = context.ParseStatements(statements); - var oldSyntax = context.GetSelectedSyntax(true); - var newSyntax = context.Service.AddStatements(oldSyntax, parsedStatements, codeGenerationOptions); - context.Result = context.Document.WithSyntaxRoot((await context.Document.GetSyntaxRootAsync()).ReplaceNode(oldSyntax, newSyntax)); + using var testContext = await TestContext.CreateAsync(initial, expected); + var parsedStatements = testContext.ParseStatements(statements); + var oldSyntax = testContext.GetSelectedSyntax(true); + var options = await CodeGenerationOptions.FromDocumentAsync(context ?? CodeGenerationContext.Default, testContext.Document, CancellationToken.None); + var newSyntax = testContext.Service.AddStatements(oldSyntax, parsedStatements, options, CancellationToken.None); + testContext.Result = testContext.Document.WithSyntaxRoot((await testContext.Document.GetSyntaxRootAsync()).ReplaceNode(oldSyntax, newSyntax)); } internal static async Task TestAddParametersAsync( string initial, string expected, ImmutableArray> parameters, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { - using var context = await TestContext.CreateAsync(initial, expected); - var parameterSymbols = GetParameterSymbols(parameters, context); - var oldMemberSyntax = context.GetSelectedSyntax(true); - var newMemberSyntax = context.Service.AddParameters(oldMemberSyntax, parameterSymbols, codeGenerationOptions); - context.Result = context.Document.WithSyntaxRoot((await context.Document.GetSyntaxRootAsync()).ReplaceNode(oldMemberSyntax, newMemberSyntax)); + using var testContext = await TestContext.CreateAsync(initial, expected); + var parameterSymbols = GetParameterSymbols(parameters, testContext); + var oldMemberSyntax = testContext.GetSelectedSyntax(true); + var options = await CodeGenerationOptions.FromDocumentAsync(context ?? CodeGenerationContext.Default, testContext.Document, CancellationToken.None); + + var newMemberSyntax = testContext.Service.AddParameters(oldMemberSyntax, parameterSymbols, options, CancellationToken.None); + testContext.Result = testContext.Document.WithSyntaxRoot((await testContext.Document.GetSyntaxRootAsync()).ReplaceNode(oldMemberSyntax, newMemberSyntax)); } internal static async Task TestAddDelegateTypeAsync( @@ -283,20 +292,21 @@ internal static async Task TestAddDelegateTypeAsync( Type returnType = null, ImmutableArray typeParameters = default, ImmutableArray> parameters = default, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { - using var context = await TestContext.CreateAsync(initial, expected); - var parameterSymbols = GetParameterSymbols(parameters, context); + using var testContext = await TestContext.CreateAsync(initial, expected); + var parameterSymbols = GetParameterSymbols(parameters, testContext); var type = CodeGenerationSymbolFactory.CreateDelegateTypeSymbol( attributes: default, accessibility, modifiers, - GetTypeSymbol(returnType)(context.SemanticModel), + GetTypeSymbol(returnType)(testContext.SemanticModel), RefKind.None, name, typeParameters, parameterSymbols); - context.Result = await context.Service.AddNamedTypeAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), type, codeGenerationOptions); + + testContext.Result = await testContext.Service.AddNamedTypeAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), type, context ?? CodeGenerationContext.Default, CancellationToken.None); } internal static async Task TestAddEventAsync( @@ -312,24 +322,25 @@ internal static async Task TestAddEventAsync( IMethodSymbol addMethod = null, IMethodSymbol removeMethod = null, IMethodSymbol raiseMethod = null, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { - using var context = await TestContext.CreateAsync(initial, expected); + using var testContext = await TestContext.CreateAsync(initial, expected); type ??= typeof(Action); - var parameterSymbols = GetParameterSymbols(parameters, context); - var typeSymbol = GetTypeSymbol(type)(context.SemanticModel); + var parameterSymbols = GetParameterSymbols(parameters, testContext); + var typeSymbol = GetTypeSymbol(type)(testContext.SemanticModel); var @event = CodeGenerationSymbolFactory.CreateEventSymbol( attributes, accessibility, modifiers, typeSymbol, - getExplicitInterfaceImplementations?.Invoke(context.SemanticModel) ?? default, + getExplicitInterfaceImplementations?.Invoke(testContext.SemanticModel) ?? default, name, addMethod, removeMethod, raiseMethod); - context.Result = await context.Service.AddEventAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), @event, codeGenerationOptions); + + testContext.Result = await testContext.Service.AddEventAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), @event, context ?? CodeGenerationContext.Default, CancellationToken.None); } internal static async Task TestAddPropertyAsync( @@ -345,7 +356,7 @@ internal static async Task TestAddPropertyAsync( ImmutableArray explicitInterfaceImplementations = default, ImmutableArray> parameters = default, bool isIndexer = false, - CodeGenerationOptions codeGenerationOptions = null, + CodeGenerationContext context = null, IDictionary options = null) { // This assumes that tests will not use place holders for get/set statements at the same time @@ -359,8 +370,8 @@ internal static async Task TestAddPropertyAsync( expected = expected.Replace("$$", setStatements); } - using var context = await TestContext.CreateAsync(initial, expected); - var workspace = context.Workspace; + using var testContext = await TestContext.CreateAsync(initial, expected); + var workspace = testContext.Workspace; if (options != null) { var optionSet = workspace.Options; @@ -370,11 +381,11 @@ internal static async Task TestAddPropertyAsync( workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(optionSet)); } - var typeSymbol = GetTypeSymbol(type)(context.SemanticModel); - var getParameterSymbols = GetParameterSymbols(parameters, context); + var typeSymbol = GetTypeSymbol(type)(testContext.SemanticModel); + var getParameterSymbols = GetParameterSymbols(parameters, testContext); var setParameterSymbols = getParameterSymbols == null ? default - : getParameterSymbols.Add(Parameter(type, "value")(context.SemanticModel)); + : getParameterSymbols.Add(Parameter(type, "value")(testContext.SemanticModel)); var getAccessor = CodeGenerationSymbolFactory.CreateMethodSymbol( attributes: default, defaultAccessibility, @@ -385,18 +396,18 @@ internal static async Task TestAddPropertyAsync( "get_" + name, typeParameters: default, getParameterSymbols, - statements: context.ParseStatements(getStatements)); + statements: testContext.ParseStatements(getStatements)); var setAccessor = CodeGenerationSymbolFactory.CreateMethodSymbol( attributes: default, setterAccessibility, new Editing.DeclarationModifiers(isAbstract: setStatements == null), - GetTypeSymbol(typeof(void))(context.SemanticModel), + GetTypeSymbol(typeof(void))(testContext.SemanticModel), RefKind.None, explicitInterfaceImplementations: default, "set_" + name, typeParameters: default, setParameterSymbols, - statements: context.ParseStatements(setStatements)); + statements: testContext.ParseStatements(setStatements)); // If get is provided but set isn't, we don't want an accessor for set if (getStatements != null && setStatements == null) @@ -423,9 +434,7 @@ internal static async Task TestAddPropertyAsync( setAccessor, isIndexer); - codeGenerationOptions ??= new CodeGenerationOptions(); - codeGenerationOptions = codeGenerationOptions.With(options: codeGenerationOptions.Options ?? workspace.Options); - context.Result = await context.Service.AddPropertyAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), property, codeGenerationOptions); + testContext.Result = await testContext.Service.AddPropertyAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), property, context ?? CodeGenerationContext.Default, CancellationToken.None); } internal static async Task TestAddNamedTypeAsync( @@ -440,14 +449,15 @@ internal static async Task TestAddNamedTypeAsync( ImmutableArray interfaces = default, SpecialType specialType = SpecialType.None, ImmutableArray> members = default, - CodeGenerationOptions codeGenerationOptions = null) + CodeGenerationContext context = null) { - using var context = await TestContext.CreateAsync(initial, expected); - var memberSymbols = GetSymbols(members, context); + using var testContext = await TestContext.CreateAsync(initial, expected); + var memberSymbols = GetSymbols(members, testContext); var type = CodeGenerationSymbolFactory.CreateNamedTypeSymbol( attributes: default, accessibility, modifiers, typeKind, name, typeParameters, baseType, interfaces, specialType, memberSymbols); - context.Result = await context.Service.AddNamedTypeAsync(context.Solution, (INamespaceSymbol)context.GetDestination(), type, codeGenerationOptions); + + testContext.Result = await testContext.Service.AddNamedTypeAsync(testContext.Solution, (INamespaceSymbol)testContext.GetDestination(), type, context ?? CodeGenerationContext.Default, CancellationToken.None); } internal static async Task TestAddAttributeAsync( @@ -456,12 +466,14 @@ internal static async Task TestAddAttributeAsync( Type attributeClass, SyntaxToken? target = null) { - using var context = await TestContext.CreateAsync(initial, expected); - var attr = CodeGenerationSymbolFactory.CreateAttributeData(GetTypeSymbol(attributeClass)(context.SemanticModel)); - var oldNode = context.GetDestinationNode(); - var newNode = CodeGenerator.AddAttributes(oldNode, context.Document.Project.Solution.Workspace, new[] { attr }, target) + using var testContext = await TestContext.CreateAsync(initial, expected); + var attr = CodeGenerationSymbolFactory.CreateAttributeData(GetTypeSymbol(attributeClass)(testContext.SemanticModel)); + var oldNode = testContext.GetDestinationNode(); + var codeGenerator = testContext.Document.GetRequiredLanguageService(); + var options = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, testContext.Document, CancellationToken.None); + var newNode = codeGenerator.AddAttributes(oldNode, new[] { attr }, target, options, CancellationToken.None) .WithAdditionalAnnotations(Formatter.Annotation); - context.Result = context.Document.WithSyntaxRoot(context.SemanticModel.SyntaxTree.GetRoot().ReplaceNode(oldNode, newNode)); + testContext.Result = testContext.Document.WithSyntaxRoot(testContext.SemanticModel.SyntaxTree.GetRoot().ReplaceNode(oldNode, newNode)); } internal static async Task TestRemoveAttributeAsync( @@ -469,15 +481,17 @@ internal static async Task TestRemoveAttributeAsync( string expected, Type attributeClass) where T : SyntaxNode { - using var context = await TestContext.CreateAsync(initial, expected); - var attributeType = GetTypeSymbol(attributeClass)(context.SemanticModel); - var taggedNode = context.GetDestinationNode(); - var attributeTarget = context.SemanticModel.GetDeclaredSymbol(taggedNode); + using var testContext = await TestContext.CreateAsync(initial, expected); + var attributeType = GetTypeSymbol(attributeClass)(testContext.SemanticModel); + var taggedNode = testContext.GetDestinationNode(); + var attributeTarget = testContext.SemanticModel.GetDeclaredSymbol(taggedNode); var attribute = attributeTarget.GetAttributes().Single(attr => Equals(attr.AttributeClass, attributeType)); var declarationNode = taggedNode.FirstAncestorOrSelf(); - var newNode = CodeGenerator.RemoveAttribute(declarationNode, context.Document.Project.Solution.Workspace, attribute) + var codeGenerator = testContext.Document.GetRequiredLanguageService(); + var options = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, testContext.Document, CancellationToken.None); + var newNode = codeGenerator.RemoveAttribute(declarationNode, attribute, options, CancellationToken.None) .WithAdditionalAnnotations(Formatter.Annotation); - context.Result = context.Document.WithSyntaxRoot(context.SemanticModel.SyntaxTree.GetRoot().ReplaceNode(declarationNode, newNode)); + testContext.Result = testContext.Document.WithSyntaxRoot(testContext.SemanticModel.SyntaxTree.GetRoot().ReplaceNode(declarationNode, newNode)); } internal static async Task TestUpdateDeclarationAsync( @@ -490,27 +504,28 @@ internal static async Task TestUpdateDeclarationAsync( bool? declareNewMembersAtTop = null, string retainedMembersKey = "RetainedMember") where T : SyntaxNode { - using var context = await TestContext.CreateAsync(initial, expected); - var declarationNode = context.GetDestinationNode().FirstAncestorOrSelf(); + using var testContext = await TestContext.CreateAsync(initial, expected); + var declarationNode = testContext.GetDestinationNode().FirstAncestorOrSelf(); var updatedDeclarationNode = declarationNode; - var workspace = context.Document.Project.Solution.Workspace; + var codeGenerator = testContext.Document.GetRequiredLanguageService(); + var options = await CodeGenerationOptions.FromDocumentAsync(new CodeGenerationContext(reuseSyntax: true), testContext.Document, CancellationToken.None); if (accessibility.HasValue) { - updatedDeclarationNode = CodeGenerator.UpdateDeclarationAccessibility(declarationNode, workspace, accessibility.Value); + updatedDeclarationNode = codeGenerator.UpdateDeclarationAccessibility(declarationNode, accessibility.Value, options, CancellationToken.None); } else if (modifiers != null) { - updatedDeclarationNode = CodeGenerator.UpdateDeclarationModifiers(declarationNode, workspace, modifiers); + updatedDeclarationNode = codeGenerator.UpdateDeclarationModifiers(declarationNode, modifiers, options, CancellationToken.None); } else if (getType != null) { - updatedDeclarationNode = CodeGenerator.UpdateDeclarationType(declarationNode, workspace, getType(context.SemanticModel)); + updatedDeclarationNode = codeGenerator.UpdateDeclarationType(declarationNode, getType(testContext.SemanticModel), options, CancellationToken.None); } else if (getNewMembers != null) { - var retainedMembers = context.GetAnnotatedDeclaredSymbols(retainedMembersKey, context.SemanticModel); - var newMembersToAdd = GetSymbols(getNewMembers, context); + var retainedMembers = testContext.GetAnnotatedDeclaredSymbols(retainedMembersKey, testContext.SemanticModel); + var newMembersToAdd = GetSymbols(getNewMembers, testContext); var allMembers = new List(); if (declareNewMembersAtTop.HasValue && declareNewMembersAtTop.Value) { @@ -523,11 +538,11 @@ internal static async Task TestUpdateDeclarationAsync( allMembers.AddRange(newMembersToAdd); } - updatedDeclarationNode = CodeGenerator.UpdateDeclarationMembers(declarationNode, workspace, allMembers); + updatedDeclarationNode = codeGenerator.UpdateDeclarationMembers(declarationNode, allMembers, options, CancellationToken.None); } updatedDeclarationNode = updatedDeclarationNode.WithAdditionalAnnotations(Formatter.Annotation); - context.Result = context.Document.WithSyntaxRoot(context.SemanticModel.SyntaxTree.GetRoot().ReplaceNode(declarationNode, updatedDeclarationNode)); + testContext.Result = testContext.Document.WithSyntaxRoot(testContext.SemanticModel.SyntaxTree.GetRoot().ReplaceNode(declarationNode, updatedDeclarationNode)); } internal static async Task TestGenerateFromSourceSymbolAsync( @@ -535,36 +550,34 @@ internal static async Task TestGenerateFromSourceSymbolAsync( string initial, string expected, bool onlyGenerateMembers = false, - CodeGenerationOptions codeGenerationOptions = null, + CodeGenerationContext context = null, string forceLanguage = null) { - using var context = await TestContext.CreateAsync(initial, expected, forceLanguage); + using var testContext = await TestContext.CreateAsync(initial, expected, forceLanguage); var destSpan = new TextSpan(); MarkupTestFile.GetSpan(symbolSource.NormalizeLineEndings(), out symbolSource, out destSpan); var projectId = ProjectId.CreateNewId(); var documentId = DocumentId.CreateNewId(projectId); - var semanticModel = await context.Solution + var semanticModel = await testContext.Solution .AddProject(projectId, "GenerationSource", "GenerationSource", TestContext.GetLanguage(symbolSource)) .AddDocument(documentId, "Source.cs", symbolSource) .GetDocument(documentId) .GetSemanticModelAsync(); - var docOptions = await context.Document.GetOptionsAsync(); - codeGenerationOptions ??= new CodeGenerationOptions(); - codeGenerationOptions = codeGenerationOptions.With(options: codeGenerationOptions.Options ?? docOptions); + context ??= CodeGenerationContext.Default; var symbol = TestContext.GetSelectedSymbol(destSpan, semanticModel); - var destination = context.GetDestination(); + var destination = testContext.GetDestination(); if (destination.IsType) { var members = onlyGenerateMembers ? symbol.GetMembers().ToArray() : new[] { symbol }; - context.Result = await context.Service.AddMembersAsync(context.Solution, (INamedTypeSymbol)destination, members, codeGenerationOptions); + testContext.Result = await testContext.Service.AddMembersAsync(testContext.Solution, (INamedTypeSymbol)destination, members, context, CancellationToken.None); } else { - context.Result = await context.Service.AddNamespaceOrTypeAsync(context.Solution, (INamespaceSymbol)destination, symbol, codeGenerationOptions); + testContext.Result = await testContext.Service.AddNamespaceOrTypeAsync(testContext.Solution, (INamespaceSymbol)destination, symbol, context, CancellationToken.None); } } diff --git a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs index c71af5b7f09a4..7029f5bbc819b 100644 --- a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs +++ b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs @@ -43,7 +43,8 @@ public async Task TestProjectRefactoringAsync() var reference = new StubAnalyzerReference(); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); - var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); + var options = CodeActionOptions.Default; + var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); var stubRefactoringAction = refactorings.Single(refactoring => refactoring.CodeActions.FirstOrDefault().action?.Title == nameof(StubRefactoring)); Assert.True(stubRefactoringAction is object); @@ -66,7 +67,8 @@ 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 result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); + var options = CodeActionOptions.Default; + var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); Assert.True(extensionManager.IsDisabled(codeRefactoring)); Assert.False(extensionManager.IsIgnored(codeRefactoring)); diff --git a/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs b/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs index fad133d60f2c3..65bc08d2849ba 100644 --- a/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs +++ b/src/EditorFeatures/Test/Completion/CompletionServiceTests.cs @@ -45,9 +45,9 @@ void Method() { var document = project.Documents.Single(); var caretPosition = workspace.DocumentWithCursor.CursorPosition ?? throw new InvalidOperationException(); - var (completions, _) = await completionService.GetCompletionsInternalAsync(document, caretPosition, CompletionOptions.Default); + var completions = await completionService.GetCompletionsAsync(document, caretPosition, CompletionOptions.Default, OptionValueSet.Empty); - Assert.NotNull(completions); + Assert.False(completions.IsEmpty); var item = Assert.Single(completions.Items.Where(item => item.ProviderName == typeof(DebugAssertTestCompletionProvider).FullName)); Assert.Equal("Assertion failed", item.DisplayText); } diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index b1a8a2ae99378..ca53019832194 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Immutable; using System.Linq; -using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -21,7 +20,6 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote.Diagnostics; -using Microsoft.CodeAnalysis.Remote.Testing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.SolutionCrawler; @@ -40,7 +38,8 @@ public class DiagnosticAnalyzerServiceTests { private static readonly TestComposition s_featuresCompositionWithMockDiagnosticUpdateSourceRegistrationService = FeaturesTestCompositions.Features .AddExcludedPartTypes(typeof(IDiagnosticUpdateSourceRegistrationService)) - .AddParts(typeof(MockDiagnosticUpdateSourceRegistrationService)); + .AddParts(typeof(MockDiagnosticUpdateSourceRegistrationService)) + .AddParts(typeof(TestDocumentTrackingService)); private static readonly TestComposition s_editorFeaturesCompositionWithMockDiagnosticUpdateSourceRegistrationService = EditorTestCompositions.EditorFeatures .AddExcludedPartTypes(typeof(IDiagnosticUpdateSourceRegistrationService)) @@ -49,6 +48,14 @@ public class DiagnosticAnalyzerServiceTests private static AdhocWorkspace CreateWorkspace(Type[] additionalParts = null) => new AdhocWorkspace(s_featuresCompositionWithMockDiagnosticUpdateSourceRegistrationService.AddParts(additionalParts).GetHostServices()); + private static void OpenDocumentAndMakeActive(Document document, Workspace workspace) + { + workspace.OpenDocument(document.Id); + + var documentTrackingService = (TestDocumentTrackingService)workspace.Services.GetRequiredService(); + documentTrackingService.SetActiveDocument(document.Id); + } + [Fact] public async Task TestHasSuccessfullyLoadedBeingFalse() { @@ -93,8 +100,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseFSAOn() workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(options).WithAnalyzerReferences(new[] { analyzerReference })); var document = GetDocumentFromIncompleteProject(workspace); - // open document - workspace.OpenDocument(document.Id); + OpenDocumentAndMakeActive(document, workspace); await TestAnalyzerAsync(workspace, document, AnalyzerResultSetter, expectedSyntax: true, expectedSemantic: true); } @@ -109,8 +115,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseWhenFileOpened() var document = GetDocumentFromIncompleteProject(workspace); - // open document - workspace.OpenDocument(document.Id); + OpenDocumentAndMakeActive(document, workspace); await TestAnalyzerAsync(workspace, document, AnalyzerResultSetter, expectedSyntax: true, expectedSemantic: true); } @@ -652,8 +657,9 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool switch (analysisScope) { + case BackgroundAnalysisScope.None: case BackgroundAnalysisScope.ActiveFile: - case BackgroundAnalysisScope.OpenFilesAndProjects: + case BackgroundAnalysisScope.OpenFiles: workspace.OpenAdditionalDocument(firstAdditionalDocument.Id); await incrementalAnalyzer.AnalyzeNonSourceDocumentAsync(firstAdditionalDocument, InvocationReasons.SyntaxChanged, CancellationToken.None); break; @@ -670,9 +676,9 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool var expectedCount = (analysisScope, testMultiple) switch { - (BackgroundAnalysisScope.ActiveFile, _) => 0, - (BackgroundAnalysisScope.OpenFilesAndProjects or BackgroundAnalysisScope.FullSolution, false) => 1, - (BackgroundAnalysisScope.OpenFilesAndProjects, true) => 2, + (BackgroundAnalysisScope.ActiveFile or BackgroundAnalysisScope.None, _) => 0, + (BackgroundAnalysisScope.OpenFiles or BackgroundAnalysisScope.FullSolution, false) => 1, + (BackgroundAnalysisScope.OpenFiles, true) => 2, (BackgroundAnalysisScope.FullSolution, true) => 4, _ => throw ExceptionUtilities.Unreachable, }; @@ -687,11 +693,11 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool var applicableDiagnostics = diagnostics.Where( d => d.Id == analyzer.Descriptor.Id && d.DataLocation.OriginalFilePath == additionalDoc.FilePath); - if (analysisScope == BackgroundAnalysisScope.ActiveFile) + if (analysisScope is BackgroundAnalysisScope.ActiveFile or BackgroundAnalysisScope.None) { Assert.Empty(applicableDiagnostics); } - else if (analysisScope == BackgroundAnalysisScope.OpenFilesAndProjects && + else if (analysisScope == BackgroundAnalysisScope.OpenFiles && firstAdditionalDocument != additionalDoc) { Assert.Empty(applicableDiagnostics); @@ -761,6 +767,7 @@ internal async Task TestDiagnosticSuppressor(bool includeAnalyzer, bool includeS switch (analysisScope) { + case BackgroundAnalysisScope.None: case BackgroundAnalysisScope.ActiveFile: workspace.OpenDocument(document.Id); var documentTrackingService = (TestDocumentTrackingService)workspace.Services.GetService(); @@ -768,7 +775,7 @@ internal async Task TestDiagnosticSuppressor(bool includeAnalyzer, bool includeS await incrementalAnalyzer.AnalyzeDocumentAsync(document, bodyOpt: null, InvocationReasons.SemanticChanged, CancellationToken.None); break; - case BackgroundAnalysisScope.OpenFilesAndProjects: + case BackgroundAnalysisScope.OpenFiles: workspace.OpenDocument(document.Id); await incrementalAnalyzer.AnalyzeDocumentAsync(document, bodyOpt: null, InvocationReasons.SemanticChanged, CancellationToken.None); break; @@ -776,11 +783,14 @@ internal async Task TestDiagnosticSuppressor(bool includeAnalyzer, bool includeS case BackgroundAnalysisScope.FullSolution: await incrementalAnalyzer.AnalyzeProjectAsync(project, semanticsChanged: true, InvocationReasons.Reanalyze, CancellationToken.None); break; + + default: + throw ExceptionUtilities.UnexpectedValue(analysisScope); } await ((AsynchronousOperationListener)service.Listener).ExpeditedWaitAsync(); - if (includeAnalyzer) + if (includeAnalyzer && analysisScope != BackgroundAnalysisScope.None) { Assert.True(diagnostic != null); Assert.Equal(NamedTypeAnalyzer.DiagnosticId, diagnostic.Id); @@ -863,6 +873,7 @@ void M() switch (analysisScope) { + case BackgroundAnalysisScope.None: case BackgroundAnalysisScope.ActiveFile: workspace.OpenDocument(document.Id); var documentTrackingService = (TestDocumentTrackingService)workspace.Services.GetRequiredService(); @@ -870,7 +881,7 @@ void M() await incrementalAnalyzer.AnalyzeDocumentAsync(document, bodyOpt: null, InvocationReasons.SemanticChanged, CancellationToken.None); break; - case BackgroundAnalysisScope.OpenFilesAndProjects: + case BackgroundAnalysisScope.OpenFiles: workspace.OpenDocument(document.Id); await incrementalAnalyzer.AnalyzeDocumentAsync(document, bodyOpt: null, InvocationReasons.SemanticChanged, CancellationToken.None); break; @@ -882,21 +893,29 @@ void M() await ((AsynchronousOperationListener)service.Listener).ExpeditedWaitAsync(); - Assert.Equal(2, diagnostics.Count); var root = await document.GetSyntaxRootAsync(); - if (testPragma) + if (analysisScope == BackgroundAnalysisScope.None) { - var pragma1 = root.FindTrivia(diagnostics[0].GetTextSpan().Start).ToString(); - Assert.Equal($"#pragma warning disable {NamedTypeAnalyzer.DiagnosticId} // Unnecessary", pragma1); - var pragma2 = root.FindTrivia(diagnostics[1].GetTextSpan().Start).ToString(); - Assert.Equal($"#pragma warning disable CS0168 // Variable is declared but never used - Unnecessary", pragma2); + // Anayzers are disabled for BackgroundAnalysisScope.None. + Assert.Empty(diagnostics); } else { - var attribute1 = root.FindNode(diagnostics[0].GetTextSpan()).ToString(); - Assert.Equal($@"System.Diagnostics.CodeAnalysis.SuppressMessage(""Category2"", ""{NamedTypeAnalyzer.DiagnosticId}"")", attribute1); - var attribute2 = root.FindNode(diagnostics[1].GetTextSpan()).ToString(); - Assert.Equal($@"System.Diagnostics.CodeAnalysis.SuppressMessage(""Category3"", ""CS0168"")", attribute2); + Assert.Equal(2, diagnostics.Count); + if (testPragma) + { + var pragma1 = root.FindTrivia(diagnostics[0].GetTextSpan().Start).ToString(); + Assert.Equal($"#pragma warning disable {NamedTypeAnalyzer.DiagnosticId} // Unnecessary", pragma1); + var pragma2 = root.FindTrivia(diagnostics[1].GetTextSpan().Start).ToString(); + Assert.Equal($"#pragma warning disable CS0168 // Variable is declared but never used - Unnecessary", pragma2); + } + else + { + var attribute1 = root.FindNode(diagnostics[0].GetTextSpan()).ToString(); + Assert.Equal($@"System.Diagnostics.CodeAnalysis.SuppressMessage(""Category2"", ""{NamedTypeAnalyzer.DiagnosticId}"")", attribute1); + var attribute2 = root.FindNode(diagnostics[1].GetTextSpan()).ToString(); + Assert.Equal($@"System.Diagnostics.CodeAnalysis.SuppressMessage(""Category3"", ""CS0168"")", attribute2); + } } } @@ -944,7 +963,7 @@ void M() var incrementalAnalyzer = (DiagnosticIncrementalAnalyzer)service.CreateIncrementalAnalyzer(workspace); - workspace.OpenDocument(document.Id); + OpenDocumentAndMakeActive(document, workspace); // First invoke analysis with cancellation token, and verify canceled compilation and no reported diagnostics. Assert.Empty(analyzer.CanceledCompilations); diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticDataTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticDataTests.cs index 63ede8d678a31..6997ff49026ae 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticDataTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticDataTests.cs @@ -114,7 +114,6 @@ private static async Task VerifyTextSpanAsync(string code, int startLine, int st id: "test1", category: "Test", message: "test1 message", - enuMessageForBingSearch: "test1 message format", severity: DiagnosticSeverity.Info, defaultSeverity: DiagnosticSeverity.Info, isEnabledByDefault: false, @@ -150,7 +149,6 @@ public async Task DiagnosticData_ExternalAdditionalLocationIsPreserved() id: "test1", category: "Test", message: "test1 message", - enuMessageForBingSearch: "test1 message format", severity: DiagnosticSeverity.Info, defaultSeverity: DiagnosticSeverity.Info, isEnabledByDefault: true, diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs index 08b025fd05645..ff12d20e85ad5 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs @@ -47,16 +47,18 @@ public async Task TestGetDiagnostics1() var id = Tuple.Create(workspace, document); var diagnostic = RaiseDiagnosticEvent(mutex, source, workspace, document.Project.Id, document.Id, id); - var data1 = await diagnosticService.GetPushDiagnosticsAsync(workspace, null, null, null, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var diagnosticMode = DiagnosticMode.Default; + + var data1 = await diagnosticService.GetPushDiagnosticsAsync(workspace, null, null, null, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(diagnostic, data1.Single()); - var data2 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, null, null, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var data2 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, null, null, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(diagnostic, data2.Single()); - var data3 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, document.Id, null, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var data3 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, document.Id, null, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(diagnostic, data3.Single()); - var data4 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, document.Id, id, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var data4 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, document.Id, id, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(diagnostic, data4.Single()); } @@ -86,19 +88,21 @@ public async Task TestGetDiagnostics2() RaiseDiagnosticEvent(mutex, source, workspace, document.Project.Id, null, id3); RaiseDiagnosticEvent(mutex, source, workspace, null, null, Tuple.Create(workspace)); - var data1 = await diagnosticService.GetPushDiagnosticsAsync(workspace, null, null, null, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var diagnosticMode = DiagnosticMode.Default; + + var data1 = await diagnosticService.GetPushDiagnosticsAsync(workspace, null, null, null, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(5, data1.Count()); - var data2 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, null, null, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var data2 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, null, null, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(4, data2.Count()); - var data3 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, null, id3, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var data3 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, null, id3, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(1, data3.Count()); - var data4 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, document.Id, null, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var data4 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, document.Id, null, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(2, data4.Count()); - var data5 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, document.Id, id, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var data5 = await diagnosticService.GetPushDiagnosticsAsync(workspace, document.Project.Id, document.Id, id, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(1, data5.Count()); } @@ -128,8 +132,10 @@ public async Task TestCleared() RaiseDiagnosticEvent(mutex, source2, workspace, document.Project.Id, null, Tuple.Create(workspace, document.Project)); RaiseDiagnosticEvent(mutex, source2, workspace, null, null, Tuple.Create(workspace)); + var diagnosticMode = DiagnosticMode.Default; + // confirm data is there. - var data1 = await diagnosticService.GetPushDiagnosticsAsync(workspace, null, null, null, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var data1 = await diagnosticService.GetPushDiagnosticsAsync(workspace, null, null, null, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(5, data1.Count()); diagnosticService.DiagnosticsUpdated -= MarkSet; @@ -144,7 +150,7 @@ public async Task TestCleared() mutex.WaitOne(); // confirm there are 2 data left - var data2 = await diagnosticService.GetPushDiagnosticsAsync(workspace, null, null, null, includeSuppressedDiagnostics: false, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None); + var data2 = await diagnosticService.GetPushDiagnosticsAsync(workspace, null, null, null, includeSuppressedDiagnostics: false, diagnosticMode, CancellationToken.None); Assert.Equal(2, data2.Count()); void MarkCalled(object sender, DiagnosticsUpdatedArgs args) @@ -182,7 +188,6 @@ private static DiagnosticData CreateDiagnosticData(ProjectId projectId, Document id: "test1", category: "Test", message: "test1 message", - enuMessageForBingSearch: "test1 message format", severity: DiagnosticSeverity.Info, defaultSeverity: DiagnosticSeverity.Info, isEnabledByDefault: false, diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index 02c55dcec4e8c..415e26de04dc4 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -71,8 +71,11 @@ public class IDEDiagnosticIDConfigurationTests private static void ValidateHelpLinkForDiagnostic(string diagnosticId, string helpLinkUri) { if (diagnosticId is "IDE0043" // Intentionally undocumented because it's being removed in favor of CA2241 - or "IDE1007" or "RemoveUnnecessaryImportsFixable" - or "RE0001") // Tracked by https://github.com/dotnet/roslyn/issues/48530 + or "IDE1007" + or "RemoveUnnecessaryImportsFixable" + or "RE0001" + or "JSON001" + or "JSON002") // Tracked by https://github.com/dotnet/roslyn/issues/48530 { Assert.True(helpLinkUri == string.Empty, $"Expected empty help link for {diagnosticId}"); return; @@ -429,6 +432,12 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable() # IDE0180 dotnet_diagnostic.IDE0180.severity = %value% +# IDE0190 +dotnet_diagnostic.IDE0190.severity = %value% + +# IDE0200 +dotnet_diagnostic.IDE0200.severity = %value% + # IDE2000 dotnet_diagnostic.IDE2000.severity = %value% @@ -446,6 +455,12 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable() # RE0001 dotnet_diagnostic.RE0001.severity = %value% + +# JSON001 +dotnet_diagnostic.JSON001.severity = %value% + +# JSON002 +dotnet_diagnostic.JSON002.severity = %value% "; VerifyConfigureSeverityCore(expected, LanguageNames.CSharp); @@ -604,6 +619,12 @@ public void VisualBasic_VerifyIDEDiagnosticSeveritiesAreConfigurable() # RE0001 dotnet_diagnostic.RE0001.severity = %value% + +# JSON001 +dotnet_diagnostic.JSON001.severity = %value% + +# JSON002 +dotnet_diagnostic.JSON002.severity = %value% "; VerifyConfigureSeverityCore(expected, LanguageNames.VisualBasic); } @@ -1010,6 +1031,12 @@ No editorconfig based code style option # IDE0180, PreferTupleSwap csharp_style_prefer_tuple_swap = true +# IDE0190, PreferParameterNullChecking +csharp_style_prefer_parameter_null_checking = true + +# IDE0200, PreferMethodGroupConversion +csharp_style_prefer_method_group_conversion = true + # IDE1005, PreferConditionalDelegateCall csharp_style_conditional_delegate_call = true @@ -1036,6 +1063,12 @@ No editorconfig based code style option # RE0001 No editorconfig based code style option + +# JSON001 +No editorconfig based code style option + +# JSON002 +No editorconfig based code style option "; VerifyConfigureCodeStyleOptionsCore(expected, LanguageNames.CSharp); @@ -1236,6 +1269,12 @@ No editorconfig based code style option # RE0001 No editorconfig based code style option + +# JSON001 +No editorconfig based code style option + +# JSON002 +No editorconfig based code style option "; VerifyConfigureCodeStyleOptionsCore(expected, LanguageNames.VisualBasic); diff --git a/src/EditorFeatures/Test/Diagnostics/MockDiagnosticService.cs b/src/EditorFeatures/Test/Diagnostics/MockDiagnosticService.cs index b3116b972beb2..4ef22ccc05c09 100644 --- a/src/EditorFeatures/Test/Diagnostics/MockDiagnosticService.cs +++ b/src/EditorFeatures/Test/Diagnostics/MockDiagnosticService.cs @@ -35,14 +35,14 @@ public MockDiagnosticService() [Obsolete] public ImmutableArray GetDiagnostics(Workspace workspace, ProjectId? projectId, DocumentId? documentId, object? id, bool includeSuppressedDiagnostics, CancellationToken cancellationToken) - => GetPushDiagnosticsAsync(workspace, projectId, documentId, id, includeSuppressedDiagnostics, InternalDiagnosticsOptions.NormalDiagnosticMode, cancellationToken).AsTask().WaitAndGetResult_CanCallOnBackground(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, Option2 diagnosticMode, CancellationToken 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, Option2 diagnosticMode, CancellationToken cancellationToken) + public ValueTask> GetPushDiagnosticsAsync(Workspace workspace, ProjectId? projectId, DocumentId? documentId, object? id, bool includeSuppressedDiagnostics, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { return new ValueTask>(GetDiagnostics(workspace, projectId, documentId)); } @@ -55,12 +55,12 @@ private ImmutableArray GetDiagnostics(Workspace workspace, Proje return _diagnostic == null ? ImmutableArray.Empty : ImmutableArray.Create(_diagnostic); } - public ImmutableArray GetPullDiagnosticBuckets(Workspace workspace, ProjectId? projectId, DocumentId? documentId, Option2 diagnosticMode, CancellationToken cancellationToken) + public ImmutableArray GetPullDiagnosticBuckets(Workspace workspace, ProjectId? projectId, DocumentId? documentId, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { return GetDiagnosticBuckets(workspace, projectId, documentId); } - public ImmutableArray GetPushDiagnosticBuckets(Workspace workspace, ProjectId? projectId, DocumentId? documentId, Option2 diagnosticMode, CancellationToken cancellationToken) + public ImmutableArray GetPushDiagnosticBuckets(Workspace workspace, ProjectId? projectId, DocumentId? documentId, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { return GetDiagnosticBuckets(workspace, projectId, documentId); } diff --git a/src/EditorFeatures/Test/EditAndContinue/ActiveStatementsMapTests.cs b/src/EditorFeatures/Test/EditAndContinue/ActiveStatementsMapTests.cs index 658e0bb4a230c..dca97ffde089e 100644 --- a/src/EditorFeatures/Test/EditAndContinue/ActiveStatementsMapTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/ActiveStatementsMapTests.cs @@ -125,5 +125,72 @@ ManagedActiveStatementDebugInfo CreateInfo(int startLine, int startColumn, int e "[134..138) -> (6,0)-(6,4) #1" }, oldSpans.Select(s => $"{s.UnmappedSpan} -> {s.Statement.Span} #{s.Statement.Ordinal}")); } + + [Fact] + public void ExpandMultiLineSpan() + { + using var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features); + + var source = @" +using System; + +class C +{ + void F() + { + G(() => + { + Console.WriteLine(1); + }); + } + + static void F(Action a) + { + a(); + } +}"; + + 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.LanguageServices.GetRequiredService(); + + var documentPathMap = new Dictionary>(); + + var moduleId = Guid.NewGuid(); + var token = 0x06000001; + ManagedActiveStatementDebugInfo CreateInfo(int startLine, int startColumn, int endLine, int endColumn) + => new(new(new(moduleId, token++, version: 1), ilOffset: 0), "a.cs", new SourceSpan(startLine, startColumn, endLine, endColumn), ActiveStatementFlags.NonLeafFrame); + + var debugInfos = ImmutableArray.Create( + CreateInfo(9, 0, 9, 34), // Console.WriteLine(1) + CreateInfo(7, 0, 10, 12), // Lambda + CreateInfo(15, 0, 15, 13) // a() + ); + + var remapping = ImmutableDictionary.CreateBuilder>(); + + CreateRegion(0, Span(9, 0, 10, 34), Span(9, 0, 9, 34)); // Current active statement doesn't move + CreateRegion(1, Span(7, 0, 10, 12), Span(7, 0, 15, 12)); // Insert 5 lines inside the lambda + CreateRegion(2, Span(15, 0, 15, 13), Span(20, 0, 20, 13)); // a() call moves down 5 lines + + var map = ActiveStatementsMap.Create(debugInfos, remapping.ToImmutable()); + + AssertEx.Equal(new[] + { + "(7,0)-(15,12)", + "(9,0)-(9,34)", + "(20,0)-(20,13)" + }, map.DocumentPathMap["a.cs"].OrderBy(s => s.Span.Start.Line).Select(s => $"{s.Span}")); + + void CreateRegion(int ordinal, SourceFileSpan oldSpan, SourceFileSpan newSpan) + => remapping.Add(debugInfos[ordinal].ActiveInstruction.Method, ImmutableArray.Create(new NonRemappableRegion(oldSpan, newSpan, isExceptionRegion: false))); + + SourceFileSpan Span(int startLine, int startColumn, int endLine, int endColumn) + => new("a.cs", new(new(startLine, startColumn), new(endLine, endColumn))); + } } } diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index 56b8af13b9482..a13cbd7ecc147 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -229,10 +229,10 @@ internal static void SetDocumentsState(DebuggingSession session, Solution soluti } private static IEnumerable InspectDiagnostics(ImmutableArray actual) - => actual.Select(d => $"{d.ProjectId} {InspectDiagnostic(d)}"); + => actual.Select(d => InspectDiagnostic(d)); private static string InspectDiagnostic(DiagnosticData diagnostic) - => $"{diagnostic.Severity} {diagnostic.Id}: {diagnostic.Message}"; + => $"{(diagnostic.DataLocation != null ? diagnostic.DataLocation.GetFileLinePositionSpan().ToString() : diagnostic.ProjectId.ToString())}: {diagnostic.Severity} {diagnostic.Id}: {diagnostic.Message}"; internal static Guid ReadModuleVersionId(Stream stream) { @@ -564,7 +564,7 @@ public async Task StartDebuggingSession_CapturingDocuments(bool captureAllDocume var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal(new[] { $"{projectP.Id} Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFileB.Path)}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{projectP.Id}: Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFileB.Path)}" }, InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); } @@ -848,9 +848,9 @@ public async Task ErrorReadingModuleFile(bool breakMode) Assert.True(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal(new[] { $"{document2.Project.Id} Error ENC1001: {string.Format(FeaturesResources.ErrorReadingFile, moduleFile.Path, expectedErrorMessage)}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{document2.Project.Id}: Error ENC1001: {string.Format(FeaturesResources.ErrorReadingFile, moduleFile.Path, expectedErrorMessage)}" }, InspectDiagnostics(emitDiagnostics)); if (breakMode) { @@ -924,7 +924,7 @@ public async Task ErrorReadingPdbFile() var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal(new[] { $"{project.Id} Warning ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{project.Id}: Warning ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); @@ -974,7 +974,7 @@ public async Task ErrorReadingSourceFile() var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal(new[] { $"{project.Id} Warning ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{project.Id}: Warning ENC1006: {string.Format(FeaturesResources.UnableToReadSourceFileOrPdb, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); fileLock.Dispose(); @@ -1064,6 +1064,108 @@ public async Task FileAdded(bool breakMode) } } + /// + /// + /// F5 build + /// complete + /// │ │ + /// Workspace ═════0═════╪════╪══════════1═══ + /// ▲ │ ▲ src file watcher + /// │ │ │ + /// dll/pdb ═0═══╪═════╪════1══════════╪═══ + /// │ │ ▲ │ + /// ┌───┘ │ │ │ + /// │ ┌──┼────┴──────────┘ + /// Source file ═0══════1══╪═══════════════════ + /// │ + /// Committed ═══════════╪════0══════════1═══ + /// solution + /// + /// + [Theory] + [CombinatorialData] + public async Task ModuleDisallowsEditAndContinue_NoChanges(bool breakMode) + { + var source0 = "class C1 { void M() { System.Console.WriteLine(0); } }"; + var source1 = "class C1 { void M() { System.Console.WriteLine(1); } }"; + + var dir = Temp.CreateDirectory(); + var sourceFile = dir.CreateFile("a.cs"); + + using var _ = CreateWorkspace(out var solution, out var service); + + var project = solution. + AddProject("test", "test", LanguageNames.CSharp). + AddMetadataReferences(TargetFrameworkUtil.GetReferences(TargetFramework.Mscorlib40)); + + solution = project.Solution; + + // compile with source1: + var moduleId = EmitLibrary(source1, sourceFilePath: sourceFile.Path); + LoadLibraryToDebuggee(moduleId, new ManagedHotReloadAvailability(ManagedHotReloadAvailabilityStatus.NotAllowedForRuntime, "*message*")); + + // update the file with source1 before session starts: + sourceFile.WriteAllText(source1); + + // source0 is loaded to workspace before session starts: + var document0 = project.AddDocument("a.cs", SourceText.From(source0, Encoding.UTF8), filePath: sourceFile.Path); + solution = document0.Project.Solution; + + var debuggingSession = await StartDebuggingSessionAsync(service, solution, initialState: CommittedSolution.DocumentState.None); + + if (breakMode) + { + EnterBreakState(debuggingSession); + } + + // workspace is updated to new version after build completed and the session started: + solution = solution.WithDocumentText(document0.Id, SourceText.From(source1)); + + var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); + Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Empty(updates.Updates); + Assert.Empty(emitDiagnostics); + + if (breakMode) + { + ExitBreakState(debuggingSession); + } + + EndDebuggingSession(debuggingSession); + } + + [Fact] + public async Task ModuleDisallowsEditAndContinue_SourceGenerator_NoChanges() + { + var moduleId = Guid.NewGuid(); + + var source1 = @"/* GENERATE class C1 { void M() { System.Console.WriteLine(1); } } */"; + var source2 = source1; + + var generator = new TestSourceGenerator() { ExecuteImpl = GenerateSource }; + + using var _ = CreateWorkspace(out var solution, out var service); + (solution, var document) = AddDefaultTestProject(solution, source1, generator); + + _mockCompilationOutputsProvider = _ => new MockCompilationOutputs(moduleId); + + LoadLibraryToDebuggee(moduleId, new ManagedHotReloadAvailability(ManagedHotReloadAvailabilityStatus.NotAllowedForRuntime, "*message*")); + + var debuggingSession = await StartDebuggingSessionAsync(service, solution); + + EnterBreakState(debuggingSession); + + // update document with the same content: + var document1 = solution.Projects.Single().Documents.Single(); + solution = solution.WithDocumentText(document1.Id, SourceText.From(source2)); + + var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); + Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); + Assert.Empty(updates.Updates); + + EndDebuggingSession(debuggingSession); + } + [Fact] public async Task ModuleDisallowsEditAndContinue() { @@ -1082,7 +1184,6 @@ void M() var source2 = @" class C1 { - void M() { System.Console.WriteLine(9); @@ -1090,8 +1191,11 @@ void M() System.Console.WriteLine(30); } }"; + + var generator = new TestSourceGenerator() { ExecuteImpl = GenerateSource }; + using var _ = CreateWorkspace(out var solution, out var service); - (solution, var document) = AddDefaultTestProject(solution, source1); + (solution, var document) = AddDefaultTestProject(solution, source1, generator); _mockCompilationOutputsProvider = _ => new MockCompilationOutputs(moduleId); @@ -1115,9 +1219,9 @@ void M() Assert.True(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal(new[] { $"{document2.Project.Id} Error ENC2016: {string.Format(FeaturesResources.EditAndContinueDisallowedByProject, document2.Project.Name, "*message*")}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{document2.FilePath}: (5,0)-(5,32): Error ENC2016: {string.Format(FeaturesResources.EditAndContinueDisallowedByProject, document2.Project.Name, "*message*")}" }, InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); @@ -1205,7 +1309,7 @@ public async Task RudeEdits(bool breakMode) Assert.True(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1274,7 +1378,7 @@ class C { int Y => 2; } diagnostics1.Select(d => $"{d.Id}: {d.GetMessage()}")); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1331,7 +1435,7 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal(new[] { $"{project.Id} Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{project.Id}: Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); // update the file to match the build: sourceFile.WriteAllText(source0); @@ -1349,7 +1453,7 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1424,7 +1528,7 @@ public async Task RudeEdits_DocumentWithoutSequencePoints() Assert.True(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1469,7 +1573,7 @@ public async Task RudeEdits_DelayLoadedModule() Assert.True(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1485,7 +1589,7 @@ public async Task RudeEdits_DelayLoadedModule() Assert.True(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1519,7 +1623,7 @@ public async Task SyntaxError() Assert.True(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.Blocked, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status); Assert.Empty(updates.Updates); Assert.Empty(emitDiagnostics); @@ -1562,13 +1666,13 @@ public async Task SemanticError() Assert.True(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - Assert.Equal(ManagedModuleUpdateStatusEx.Blocked, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status); Assert.Empty(updates.Updates); // TODO: https://github.com/dotnet/roslyn/issues/36061 // Semantic errors should not be reported in emit diagnostics. - AssertEx.Equal(new[] { $"{document2.Project.Id} Error CS0266: {string.Format(CSharpResources.ERR_NoImplicitConvCast, "long", "int")}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{document2.FilePath}: (0,30)-(0,32): Error CS0266: {string.Format(CSharpResources.ERR_NoImplicitConvCast, "long", "int")}" }, InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); @@ -1886,7 +1990,7 @@ public async Task Capabilities_SynthesizedNewType() // They are reported as emit diagnostics var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - AssertEx.Equal(new[] { $"{document2.Project.Id} Error ENC1007: {FeaturesResources.ChangesRequiredSynthesizedType}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{document2.Project.Id}: Error ENC1007: {FeaturesResources.ChangesRequiredSynthesizedType}" }, InspectDiagnostics(emitDiagnostics)); // no emitted delta: Assert.Empty(updates.Updates); @@ -1920,7 +2024,7 @@ public async Task ValidSignificantChange_EmitError() Assert.True(await debuggingSession.EditSession.HasChangesAsync(solution, s_noActiveSpans, sourceFilePath: null, CancellationToken.None)); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - AssertEx.Equal(new[] { $"{document2.Project.Id} Error CS8055: {string.Format(CSharpResources.ERR_EncodinglessSyntaxTree)}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{document2.FilePath}: (0,0)-(0,54): Error CS8055: {string.Format(CSharpResources.ERR_EncodinglessSyntaxTree)}" }, InspectDiagnostics(emitDiagnostics)); // no emitted delta: Assert.Empty(updates.Updates); @@ -2085,7 +2189,7 @@ public async Task ValidSignificantChange_FileUpdateNotObservedBeforeDebuggingSes var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Equal(ManagedModuleUpdateStatus.None, updates.Status); - AssertEx.Equal(new[] { $"{project.Id} Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal(new[] { $"{project.Id}: Warning ENC1005: {string.Format(FeaturesResources.DocumentIsOutOfSyncWithDebuggee, sourceFile.Path)}" }, InspectDiagnostics(emitDiagnostics)); // undo: solution = solution.WithDocumentText(documentId, SourceText.From(source1, Encoding.UTF8)); @@ -3002,8 +3106,8 @@ public async Task ValidSignificantChange_BaselineCreationFailed_NoStream() solution = solution.WithDocumentText(document1.Id, SourceText.From("class C1 { void M() { System.Console.WriteLine(2); } }", Encoding.UTF8)); 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(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + 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); } [Fact] @@ -3035,8 +3139,8 @@ public async Task ValidSignificantChange_BaselineCreationFailed_AssemblyReadErro solution = solution.WithDocumentText(document1.Id, SourceText.From("class C1 { void M() { System.Console.WriteLine(2); } }", Encoding.UTF8)); 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(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + AssertEx.Equal(new[] { $"{document.Project.Id}: Error ENC1001: {string.Format(FeaturesResources.ErrorReadingFile, "test-assembly", "*message*")}" }, InspectDiagnostics(emitDiagnostics)); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); EndDebuggingSession(debuggingSession); @@ -3591,7 +3695,7 @@ int F() var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Empty(emitDiagnostics); - Assert.Equal(ManagedModuleUpdateStatusEx.RestartRequired, updates.Status); + Assert.Equal(ManagedModuleUpdateStatus.RestartRequired, updates.Status); // undo the change solution = solution.WithDocumentText(document.Id, SourceText.From(source1, Encoding.UTF8)); @@ -3680,8 +3784,8 @@ static void F() AssertEx.Equal(new[] { - $"0x06000002 v1 | AS {document.FilePath}: (4,41)-(4,42) δ=0", - $"0x06000003 v1 | AS {document.FilePath}: (9,14)-(9,18) δ=1", + $"0x06000002 v1 | AS {document.FilePath}: (4,41)-(4,42) => (4,41)-(4,42)", + $"0x06000003 v1 | AS {document.FilePath}: (9,14)-(9,18) => (10,14)-(10,18)", }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); ExitBreakState(debuggingSession); @@ -3701,8 +3805,8 @@ static void F() // the regions remain unchanged AssertEx.Equal(new[] { - $"0x06000002 v1 | AS {document.FilePath}: (4,41)-(4,42) δ=0", - $"0x06000003 v1 | AS {document.FilePath}: (9,14)-(9,18) δ=1", + $"0x06000002 v1 | AS {document.FilePath}: (4,41)-(4,42) => (4,41)-(4,42)", + $"0x06000003 v1 | AS {document.FilePath}: (9,14)-(9,18) => (10,14)-(10,18)", }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); // EnC update F v3 -> v4 @@ -3737,7 +3841,7 @@ static void F() // Stale active statement region is gone. AssertEx.Equal(new[] { - $"0x06000002 v1 | AS {document.FilePath}: (4,41)-(4,42) δ=0", + $"0x06000002 v1 | AS {document.FilePath}: (4,41)-(4,42) => (4,41)-(4,42)", }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); ExitBreakState(debuggingSession); @@ -3862,8 +3966,8 @@ static void F() AssertEx.Equal(new[] { - $"0x06000002 v1 | AS {document.FilePath}: (3,41)-(3,42) δ=0", - $"0x06000003 v1 | AS {document.FilePath}: (7,14)-(7,18) δ=2", + $"0x06000002 v1 | AS {document.FilePath}: (3,41)-(3,42) => (3,41)-(3,42)", + $"0x06000003 v1 | AS {document.FilePath}: (7,14)-(7,18) => (9,14)-(9,18)", }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); ExitBreakState(debuggingSession); diff --git a/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs index 97cbfe86a4262..036423ea9fae1 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditSessionActiveStatementsTests.cs @@ -273,11 +273,11 @@ static void Main() AssertEx.Equal(new[] { - $"0x06000004 v1 | AS {document2.FilePath}: (8,20)-(8,25) δ=1", - $"0x06000004 v1 | ER {document2.FilePath}: (14,8)-(16,9) δ=1", - $"0x06000004 v1 | ER {document2.FilePath}: (10,10)-(12,11) δ=1", - $"0x06000003 v1 | AS {document2.FilePath}: (21,14)-(21,24) δ=0", - $"0x06000005 v1 | AS {document2.FilePath}: (26,20)-(26,25) δ=0" + $"0x06000004 v1 | AS {document2.FilePath}: (8,20)-(8,25) => (9,20)-(9,25)", + $"0x06000004 v1 | ER {document2.FilePath}: (14,8)-(16,9) => (15,8)-(17,9)", + $"0x06000004 v1 | ER {document2.FilePath}: (10,10)-(12,11) => (11,10)-(13,11)", + $"0x06000003 v1 | AS {document2.FilePath}: (21,14)-(21,24) => (21,14)-(21,24)", + $"0x06000005 v1 | AS {document2.FilePath}: (26,20)-(26,25) => (26,20)-(26,25)" }, nonRemappableRegions.Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); AssertEx.Equal(new[] @@ -388,10 +388,10 @@ static void F2() AssertEx.Equal(new[] { - $"0x06000001 v1 | AS {document.FilePath}: (6,18)-(6,23) δ=0", - $"0x06000001 v1 | ER {document.FilePath}: (8,8)-(12,9) δ=0", - $"0x06000002 v1 | AS {document.FilePath}: (18,14)-(18,36) δ=0", - }, nonRemappableRegions.OrderBy(r => r.Region.Span.Span.Start.Line).Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); + $"0x06000001 v1 | AS {document.FilePath}: (6,18)-(6,23) => (6,18)-(6,23)", + $"0x06000001 v1 | ER {document.FilePath}: (8,8)-(12,9) => (8,8)-(12,9)", + $"0x06000002 v1 | AS {document.FilePath}: (18,14)-(18,36) => (18,14)-(18,36)", + }, nonRemappableRegions.OrderBy(r => r.Region.OldSpan.Span.Start.Line).Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); AssertEx.Equal(new[] { @@ -503,16 +503,16 @@ static void F4() { { new ManagedMethodId(module1, 0x06000003, 1), ImmutableArray.Create( // move AS:2 one line up: - new NonRemappableRegion(spanPreRemap2, lineDelta: -1, isExceptionRegion: false), + new NonRemappableRegion(spanPreRemap2, spanPreRemap2.AddLineDelta(-1), isExceptionRegion: false), // move ER:2.0 and ER:2.1 two lines down: - new NonRemappableRegion(erPreRemap20, lineDelta: +2, isExceptionRegion: true), - new NonRemappableRegion(erPreRemap21, lineDelta: +2, isExceptionRegion: true)) }, + new NonRemappableRegion(erPreRemap20, erPreRemap20.AddLineDelta(+2), isExceptionRegion: true), + new NonRemappableRegion(erPreRemap21, erPreRemap21.AddLineDelta(+2), isExceptionRegion: true)) }, { new ManagedMethodId(module1, 0x06000004, 1), ImmutableArray.Create( // move AS:3 one line down: - new NonRemappableRegion(spanPreRemap3, lineDelta: +1, isExceptionRegion: false), + new NonRemappableRegion(spanPreRemap3, spanPreRemap3.AddLineDelta(+1), isExceptionRegion: false), // move ER:3.0 and ER:3.1 one line down: - new NonRemappableRegion(erPreRemap30, lineDelta: +1, isExceptionRegion: true), - new NonRemappableRegion(erPreRemap31, lineDelta: +1, isExceptionRegion: true)) } + new NonRemappableRegion(erPreRemap30, erPreRemap30.AddLineDelta(+1), isExceptionRegion: true), + new NonRemappableRegion(erPreRemap31, erPreRemap31.AddLineDelta(+1), isExceptionRegion: true)) } }.ToImmutableDictionary(); using var workspace = new TestWorkspace(composition: s_composition); @@ -582,16 +582,16 @@ static void F4() // Note: Since no method have been remapped yet all the following spans are in their pre-remap locations: AssertEx.Equal(new[] { - $"0x06000001 v2 | AS {document.FilePath}: (6,18)-(6,22) δ=0", - $"0x06000002 v2 | ER {document.FilePath}: (18,16)-(21,9) δ=-1", - $"0x06000002 v2 | AS {document.FilePath}: (20,18)-(20,22) δ=-1", - $"0x06000003 v1 | AS {document.FilePath}: (30,22)-(30,26) δ=-1", // AS:2 moved -1 in first edit, 0 in second - $"0x06000003 v1 | ER {document.FilePath}: (32,20)-(34,13) δ=2", // ER:2.0 moved +2 in first edit, 0 in second - $"0x06000003 v1 | ER {document.FilePath}: (36,16)-(38,9) δ=2", // ER:2.0 moved +2 in first edit, 0 in second - $"0x06000004 v1 | ER {document.FilePath}: (50,20)-(53,13) δ=3", // ER:3.0 moved +1 in first edit, +2 in second - $"0x06000004 v1 | AS {document.FilePath}: (52,22)-(52,26) δ=3", // AS:3 moved +1 in first edit, +2 in second - $"0x06000004 v1 | ER {document.FilePath}: (55,16)-(57,9) δ=3", // ER:3.1 moved +1 in first edit, +2 in second - }, nonRemappableRegions.OrderBy(r => r.Region.Span.Span.Start.Line).Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); + $"0x06000001 v2 | AS {document.FilePath}: (6,18)-(6,22) => (6,18)-(6,22)", + $"0x06000002 v2 | ER {document.FilePath}: (18,16)-(21,9) => (17,16)-(20,9)", + $"0x06000002 v2 | AS {document.FilePath}: (20,18)-(20,22) => (19,18)-(19,22)", + $"0x06000003 v1 | AS {document.FilePath}: (30,22)-(30,26) => (29,22)-(29,26)", // AS:2 moved -1 in first edit, 0 in second + $"0x06000003 v1 | ER {document.FilePath}: (32,20)-(34,13) => (34,20)-(36,13)", // ER:2.0 moved +2 in first edit, 0 in second + $"0x06000003 v1 | ER {document.FilePath}: (36,16)-(38,9) => (38,16)-(40,9)", // ER:2.0 moved +2 in first edit, 0 in second + $"0x06000004 v1 | ER {document.FilePath}: (50,20)-(53,13) => (53,20)-(56,13)", // ER:3.0 moved +1 in first edit, +2 in second + $"0x06000004 v1 | AS {document.FilePath}: (52,22)-(52,26) => (55,22)-(55,26)", // AS:3 moved +1 in first edit, +2 in second + $"0x06000004 v1 | ER {document.FilePath}: (55,16)-(57,9) => (58,16)-(60,9)", // ER:3.1 moved +1 in first edit, +2 in second + }, nonRemappableRegions.OrderBy(r => r.Region.OldSpan.Span.Start.Line).Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); AssertEx.Equal(new[] { diff --git a/src/EditorFeatures/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs b/src/EditorFeatures/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs index 7733c1547fe3f..7cead9c1238fd 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs @@ -43,7 +43,6 @@ public async Task GetHotReloadDiagnostics() id: "CS0001", category: "Test", message: "warning", - enuMessageForBingSearch: "test2 message format", severity: DiagnosticSeverity.Warning, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true, @@ -60,7 +59,6 @@ public async Task GetHotReloadDiagnostics() id: "CS0012", category: "Test", message: "error", - enuMessageForBingSearch: "test2 message format", severity: DiagnosticSeverity.Error, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true, @@ -78,7 +76,6 @@ public async Task GetHotReloadDiagnostics() id: "CS0002", category: "Test", message: "syntax error", - enuMessageForBingSearch: "test3 message format", severity: DiagnosticSeverity.Error, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true, diff --git a/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs index 019c7f3c0fd7c..6e7c7e398273f 100644 --- a/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs @@ -163,9 +163,12 @@ void VerifyReanalyzeInvocation(ImmutableArray documentIds) documentsToReanalyze = ImmutableArray.Create(document.Id); }; - await sessionProxy.BreakStateOrCapabilitiesChangedAsync(mockDiagnosticService, inBreakState: true, CancellationToken.None).ConfigureAwait(false); + await sessionProxy.BreakStateOrCapabilitiesChangedAsync(mockDiagnosticService, diagnosticUpdateSource, inBreakState: true, CancellationToken.None).ConfigureAwait(false); VerifyReanalyzeInvocation(ImmutableArray.Create(document.Id)); + Assert.Equal(1, emitDiagnosticsClearedCount); + emitDiagnosticsClearedCount = 0; + var activeStatement = (await remoteDebuggeeModuleMetadataProvider!.GetActiveStatementsAsync(CancellationToken.None).ConfigureAwait(false)).Single(); Assert.Equal(as1.ActiveInstruction, activeStatement.ActiveInstruction); Assert.Equal(as1.SourceSpan, activeStatement.SourceSpan); diff --git a/src/EditorFeatures/Test/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetectorTests.cs b/src/EditorFeatures/Test/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetectorTests.cs new file mode 100644 index 0000000000000..daf50a13f0294 --- /dev/null +++ b/src/EditorFeatures/Test/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetectorTests.cs @@ -0,0 +1,138 @@ +// Licensed to the .NET Foundation under one or more agreements. +// 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.Features.EmbeddedLanguages.Json; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests.EmbeddedLanguages.Json.LanguageServices +{ + public class JsonLanguageDetectorTests + { + private static void Match(string value, JsonOptions? expectedOptions = null) + { + MatchWorker($"/*{value}*/", expectedOptions); + MatchWorker($"/*{value} */", expectedOptions); + MatchWorker($"//{value}", expectedOptions); + MatchWorker($"// {value}", expectedOptions); + MatchWorker($"'{value}", expectedOptions); + MatchWorker($"' {value}", expectedOptions); + + static void MatchWorker(string value, JsonOptions? expectedOptions) + { + Assert.True(JsonLanguageDetector.TestAccessor.TryMatch(value, out var actualOptions)); + + if (expectedOptions != null) + Assert.Equal(expectedOptions.Value, actualOptions); + } + } + + private static void NoMatch(string value) + { + NoMatchWorker($"/*{value}*/"); + NoMatchWorker($"/*{value} */"); + NoMatchWorker($"//{value}"); + NoMatchWorker($"// {value}"); + NoMatchWorker($"'{value}"); + NoMatchWorker($"' {value}"); + + static void NoMatchWorker(string value) + { + Assert.False(JsonLanguageDetector.TestAccessor.TryMatch(value, out _)); + } + } + + [Fact] + public void TestSimpleForm() + => Match("lang=json"); + + [Fact] + public void TestAllCaps() + => Match("lang=JSON"); + + [Fact] + public void TestIncompleteForm1() + => NoMatch("lan=json"); + + [Fact] + public void TestIncompleteForm2() + => NoMatch("lang=jso"); + + [Fact] + public void TestMissingEquals() + => NoMatch("lang json"); + + [Fact] + public void TestLanguageForm() + => Match("language=json"); + + [Fact] + public void TestLanguageNotFullySpelled() + => NoMatch("languag=json"); + + [Fact] + public void TestSpacesAroundEquals() + => Match("lang = json"); + + [Fact] + public void TestSpacesAroundPieces() + => Match(" lang=json "); + + [Fact] + public void TestSpacesAroundPiecesAndEquals() + => Match(" lang = json "); + + [Fact] + public void TestSpaceBetweenJsonAndNextWord() + => Match("lang=json here"); + + [Fact] + public void TestPeriodAtEnd() + => Match("lang=json."); + + [Fact] + public void TestNotWithWordCharAtEnd() + => NoMatch("lang=jsonc"); + + [Fact] + public void TestWithNoNWordBeforeStart1() + => NoMatch(":lang=json"); + + [Fact] + public void TestWithNoNWordBeforeStart2() + => NoMatch(": lang=json"); + + [Fact] + public void TestNotWithWordCharAtStart() + => NoMatch("clang=json"); + + [Fact] + public void TestOption() + => Match("lang=json,strict", JsonOptions.Strict); + + [Fact] + public void TestOptionWithSpaces() + => Match("lang=json , strict", JsonOptions.Strict); + + [Fact] + public void TestOptionFollowedByPeriod() + => Match("lang=json,strict. Explanation", JsonOptions.Strict); + + [Fact] + public void TestMultiOptionFollowedByPeriod() + => Match("lang=json,strict,Strict. Explanation", JsonOptions.Strict); + + [Fact] + public void TestMultiOptionFollowedByPeriod_CaseInsensitive() + => Match("Language=Json,Strict. Explanation", JsonOptions.Strict); + + [Fact] + public void TestInvalidOption1() + => NoMatch("lang=json,ignore"); + + [Fact] + public void TestInvalidOption2() + => NoMatch("lang=json,strict,ignore"); + } +} diff --git a/src/EditorFeatures/Test/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexPatternDetectorTests.cs b/src/EditorFeatures/Test/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexPatternDetectorTests.cs index 3b508248695a7..a0989044fde94 100644 --- a/src/EditorFeatures/Test/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexPatternDetectorTests.cs +++ b/src/EditorFeatures/Test/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexPatternDetectorTests.cs @@ -2,31 +2,45 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Text.RegularExpressions; -using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions.LanguageServices; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests.EmbeddedLanguages.RegularExpressions.LanguageServices { public class RegexPatternDetectorTests { - private static void Match(string value, RegexOptions? expectedOptions = null, string prefix = "//") + private static void Match(string value, RegexOptions? expectedOptions = null) { - var (matched, options) = RegexPatternDetector.TestAccessor.TryMatch(prefix + value); - Assert.True(matched); - - if (expectedOptions != null) + MatchWorker($"/*{value}*/", expectedOptions); + MatchWorker($"/*{value} */", expectedOptions); + MatchWorker($"//{value}", expectedOptions); + MatchWorker($"// {value}", expectedOptions); + MatchWorker($"'{value}", expectedOptions); + MatchWorker($"' {value}", expectedOptions); + + static void MatchWorker(string value, RegexOptions? expectedOptions) { - Assert.Equal(expectedOptions.Value, options); + Assert.True(RegexLanguageDetector.TestAccessor.TryMatch(value, out var actualOptions)); + + if (expectedOptions != null) + Assert.Equal(expectedOptions.Value, actualOptions); } } - private static void NoMatch(string value, string prefix = "//") + private static void NoMatch(string value) { - var (matched, _) = RegexPatternDetector.TestAccessor.TryMatch(prefix + value); - Assert.False(matched); + NoMatchWorker($"/*{value}*/"); + NoMatchWorker($"/*{value} */"); + NoMatchWorker($"//{value}"); + NoMatchWorker($"// {value}"); + NoMatchWorker($"'{value}"); + NoMatchWorker($"' {value}"); + + static void NoMatchWorker(string value) + { + Assert.False(RegexLanguageDetector.TestAccessor.TryMatch(value, out _)); + } } [Fact] @@ -34,12 +48,16 @@ public void TestSimpleForm() => Match("lang=regex"); [Fact] - public void TestSimpleFormVB() - => Match("' lang=regex", prefix: ""); + public void TestIncompleteForm1() + => NoMatch("lan=regex"); [Fact] - public void TestSimpleFormCSharpMultiLine() - => Match("/* lang=regex", prefix: ""); + public void TestIncompleteForm2() + => NoMatch("lang=rege"); + + [Fact] + public void TestMissingEquals() + => NoMatch("lang regex"); [Fact] public void TestEndingInP() @@ -120,9 +138,5 @@ public void TestInvalidOption1() [Fact] public void TestInvalidOption2() => NoMatch("lang=regex,ecmascript,ignore"); - - [Fact] - public void TestNotOnDocComment() - => NoMatch("/// lang=regex,ignore", prefix: ""); } } diff --git a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.Utilities.cs b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.Utilities.cs index a632795add9dc..bfcab7c530a2e 100644 --- a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.Utilities.cs +++ b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.Utilities.cs @@ -86,6 +86,12 @@ private static void FuzzyTest(string input) private static void VerifyCharacterSpans(string originalText, StackFrameTree tree) { + AssertEx.EqualOrDiff(originalText, tree.Root.ToFullString()); + + // Manually enumerate to verify that it works as expected and the spans align. + // This should be the same as ToFullString, but this tests that enumeration of the + // tokens yields the correct order (which we can't guarantee with ToFullString depending + // on implementation). var textSeq = VirtualCharSequence.Create(0, originalText); var index = 0; List enumeratedParsedCharacters = new(); diff --git a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.cs b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.cs index 666f56a11c4b0..fe234fa4bfa12 100644 --- a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.cs +++ b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameParserTests.cs @@ -439,5 +439,31 @@ public void TestKeywordsAsIdentifiers(string keyword) Identifier(keyword.Trim()), IdentifierToken(keyword.Trim(), leadingTrivia: SpaceTrivia(2), trailingTrivia: SpaceTrivia())))) ); + + [Fact] + public void TestGeneratedMain() + => Verify(@"Program.
$(String[] args)", + methodDeclaration: MethodDeclaration( + QualifiedName( + Identifier("Program"), + GeneratedName("Main")), + argumentList: ParameterList( + Parameter(ArrayType(Identifier("String"), ArrayRankSpecifier(trailingTrivia: SpaceTrivia())), + IdentifierToken("args"))) + ) + ); + + [Fact] + public void TestLocalMethod() + => Verify(@"C.g__Local|0_0()", + methodDeclaration: MethodDeclaration( + QualifiedName( + Identifier("C"), + LocalMethod( + GeneratedName("M", endWithDollar: false), + "Local", + "0_0")) + ) + ); } } diff --git a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameSyntaxFactory.cs b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameSyntaxFactory.cs index 8830e4ae412b4..58418c82bd2bd 100644 --- a/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameSyntaxFactory.cs +++ b/src/EditorFeatures/Test/EmbeddedLanguages/StackFrame/StackFrameSyntaxFactory.cs @@ -44,6 +44,8 @@ public static ImmutableArray CreateTriviaArray(params string[] public static readonly StackFrameToken GraveAccentToken = CreateToken(StackFrameKind.GraveAccentToken, "`"); public static readonly StackFrameToken EOLToken = CreateToken(StackFrameKind.EndOfFrame, ""); public static readonly StackFrameToken ColonToken = CreateToken(StackFrameKind.ColonToken, ":"); + public static readonly StackFrameToken DollarToken = CreateToken(StackFrameKind.DollarToken, "$"); + public static readonly StackFrameToken PipeToken = CreateToken(StackFrameKind.PipeToken, "|"); public static readonly StackFrameTrivia AtTrivia = CreateTrivia(StackFrameKind.AtTrivia, "at "); public static readonly StackFrameTrivia LineTrivia = CreateTrivia(StackFrameKind.LineTrivia, "line "); @@ -88,6 +90,9 @@ public static StackFrameMethodDeclarationNode MethodDeclaration( return new StackFrameMethodDeclarationNode(memberAccessExpression, typeArguments, argumentList ?? ParameterList(OpenParenToken, CloseParenToken)); } + public static StackFrameGeneratedMethodNameNode GeneratedName(string name, bool endWithDollar = true) + => new(LessThanToken, IdentifierToken(name), GreaterThanToken, endWithDollar ? DollarToken : null); + public static StackFrameQualifiedNameNode QualifiedName(string s, StackFrameTrivia? leadingTrivia = null, StackFrameTrivia? trailingTrivia = null) => QualifiedName(s, leadingTrivia.ToImmutableArray(), trailingTrivia.ToImmutableArray()); @@ -199,5 +204,13 @@ public static StackFrameToken Path(string path) public static StackFrameToken Line(int lineNumber) => CreateToken(StackFrameKind.NumberToken, lineNumber.ToString(), leadingTrivia: ImmutableArray.Create(LineTrivia)); + + public static StackFrameLocalMethodNameNode LocalMethod(StackFrameGeneratedMethodNameNode encapsulatingMethod, string identifier, string suffix) + => new( + encapsulatingMethod, + CreateToken(StackFrameKind.GeneratedNameSeparatorToken, "g__"), + IdentifierToken(identifier), + PipeToken, + CreateToken(StackFrameKind.GeneratedNameSuffixToken, suffix)); } } diff --git a/src/EditorFeatures/Test/FindReferences/FindReferencesCommandHandlerTests.cs b/src/EditorFeatures/Test/FindReferences/FindReferencesCommandHandlerTests.cs index 38bcb96c02e7b..9843a1c315aa2 100644 --- a/src/EditorFeatures/Test/FindReferences/FindReferencesCommandHandlerTests.cs +++ b/src/EditorFeatures/Test/FindReferences/FindReferencesCommandHandlerTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Text; @@ -29,7 +30,14 @@ public class FindReferencesCommandHandlerTests { private class MockFindUsagesContext : FindUsagesContext { - public readonly List Result = new List(); + public readonly List Result = new(); + + public MockFindUsagesContext() + { + } + + public override ValueTask GetOptionsAsync(string language, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(FindUsagesOptions.Default); public override ValueTask OnDefinitionFoundAsync(DefinitionItem definition, CancellationToken cancellationToken) { @@ -71,6 +79,7 @@ public async Task TestFindReferencesAsynchronousCall() var handler = new FindReferencesCommandHandler( presenter, + workspace.GlobalOptions, listenerProvider); var textView = workspace.Documents[0].GetTextView(); diff --git a/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs b/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs index 683b6ca5ec23f..ab0510ba3ed94 100644 --- a/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs +++ b/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs @@ -94,7 +94,7 @@ private static async Task VerifyInheritanceMemberAsync(TestWorkspace testWorkspa .Select(info => TestInheritanceTargetItem.Create(info, testWorkspace)) .OrderBy(target => target.TargetSymbolName) .ToImmutableArray(); - var sortedActualTargets = actualItem.TargetItems.OrderBy(target => target.DefinitionItem.DisplayParts.JoinText()) + var sortedActualTargets = actualItem.TargetItems.OrderBy(target => target.DisplayName) .ToImmutableArray(); for (var i = 0; i < expectedTargets.Length; i++) { @@ -104,7 +104,7 @@ private static async Task VerifyInheritanceMemberAsync(TestWorkspace testWorkspa private static async Task VerifyInheritanceTargetAsync(TestInheritanceTargetItem expectedTarget, InheritanceTargetItem actualTarget) { - Assert.Equal(expectedTarget.TargetSymbolName, actualTarget.DefinitionItem.DisplayParts.JoinText()); + Assert.Equal(expectedTarget.TargetSymbolName, actualTarget.DisplayName); Assert.Equal(expectedTarget.RelationshipToMember, actualTarget.RelationToMember); if (expectedTarget.IsInMetadata) @@ -123,6 +123,15 @@ private static async Task VerifyInheritanceTargetAsync(TestInheritanceTargetItem Assert.Equal(expectedDocumentSpans[i].SourceSpan, docSpan.Value.SourceSpan); Assert.Equal(expectedDocumentSpans[i].Document.FilePath, docSpan.Value.Document.FilePath); } + + if (actualDocumentSpans.Length == 1) + { + Assert.Empty(actualTarget.DefinitionItem.Tags); + Assert.Empty(actualTarget.DefinitionItem.Properties); + Assert.Empty(actualTarget.DefinitionItem.DisplayableProperties); + Assert.Empty(actualTarget.DefinitionItem.NameDisplayParts); + Assert.Empty(actualTarget.DefinitionItem.DisplayParts); + } } } @@ -184,7 +193,7 @@ public TestInheritanceMemberItem( private class TargetInfo { public readonly string TargetSymbolDisplayName; - public readonly string? LocationTag; + public readonly ImmutableArray LocationTags; public readonly InheritanceRelationship Relationship; public readonly bool InMetadata; @@ -194,7 +203,7 @@ public TargetInfo( InheritanceRelationship relationship) { TargetSymbolDisplayName = targetSymbolDisplayName; - LocationTag = locationTag; + LocationTags = ImmutableArray.Create(locationTag); Relationship = relationship; InMetadata = false; } @@ -207,7 +216,17 @@ public TargetInfo( TargetSymbolDisplayName = targetSymbolDisplayName; Relationship = relationship; InMetadata = inMetadata; - LocationTag = null; + LocationTags = ImmutableArray.Empty; + } + + public TargetInfo( + string targetSymbolDisplayName, + InheritanceRelationship relationship, + params string[] locationTags) + { + TargetSymbolDisplayName = targetSymbolDisplayName; + LocationTags = locationTags.ToImmutableArray(); + Relationship = relationship; } } @@ -246,16 +265,20 @@ public static TestInheritanceTargetItem Create( { using var _ = ArrayBuilder.GetInstance(out var builder); // If the target is not in metadata, there must be a location tag to give the span! - Assert.True(targetInfo.LocationTag != null); + Assert.True(targetInfo.LocationTags != null); foreach (var testHostDocument in testWorkspace.Documents) { - if (targetInfo.LocationTag != null) + if (targetInfo.LocationTags != null) { var annotatedSpans = testHostDocument.AnnotatedSpans; - if (annotatedSpans.TryGetValue(targetInfo.LocationTag, out var spans)) + + foreach (var tag in targetInfo.LocationTags) { - var document = testWorkspace.CurrentSolution.GetRequiredDocument(testHostDocument.Id); - builder.AddRange(spans.Select(span => new DocumentSpan(document, span))); + if (annotatedSpans.TryGetValue(tag, out var spans)) + { + var document = testWorkspace.CurrentSolution.GetRequiredDocument(testHostDocument.Id); + builder.AddRange(spans.Select(span => new DocumentSpan(document, span))); + } } } } @@ -296,7 +319,7 @@ public class Bar : IEnumerable lineNumber: 3, memberName: "class Bar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IEnumerable", + targetSymbolDisplayName: "IEnumerable", relationship: InheritanceRelationship.ImplementedInterface, inMetadata: true))); @@ -304,7 +327,7 @@ public class Bar : IEnumerable lineNumber: 5, memberName: "IEnumerator Bar.GetEnumerator()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "IEnumerator IEnumerable.GetEnumerator()", + targetSymbolDisplayName: "IEnumerable.GetEnumerator", relationship: InheritanceRelationship.ImplementedMember, inMetadata: true))); @@ -325,7 +348,7 @@ public class {|target2:Bar|} : IBar lineNumber: 2, memberName: "interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target2", relationship: InheritanceRelationship.ImplementingType))); @@ -333,7 +356,7 @@ public class {|target2:Bar|} : IBar lineNumber: 3, memberName: "class Bar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target1", relationship: InheritanceRelationship.ImplementedInterface))); @@ -356,7 +379,7 @@ interface {|target2:IBar2|} : IBar { } lineNumber: 2, memberName: "interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IBar2", + targetSymbolDisplayName: "IBar2", locationTag: "target2", relationship: InheritanceRelationship.ImplementingType)) ); @@ -365,7 +388,7 @@ interface {|target2:IBar2|} : IBar { } memberName: "interface IBar2", targets: ImmutableArray.Empty .Add(new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target1", relationship: InheritanceRelationship.InheritedInterface)) ); @@ -389,7 +412,7 @@ class {|target1:B|} : A { } lineNumber: 2, memberName: "class A", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class B", + targetSymbolDisplayName: "B", locationTag: "target1", relationship: InheritanceRelationship.DerivedType)) ); @@ -397,7 +420,7 @@ class {|target1:B|} : A { } lineNumber: 3, memberName: "class B", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class A", + targetSymbolDisplayName: "A", locationTag: "target2", relationship: InheritanceRelationship.BaseType)) ); @@ -445,7 +468,7 @@ public class Bar : Bar1 memberName: "class Bar", targets: ImmutableArray.Create( new TargetInfo( - targetSymbolDisplayName: "class Bar1", + targetSymbolDisplayName: "Bar1", locationTag: "target1", relationship: InheritanceRelationship.BaseType)))); } @@ -470,7 +493,7 @@ public class {|target1:Bar|} : IBar lineNumber: 3, memberName: "interface IBar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -478,7 +501,7 @@ public class {|target1:Bar|} : IBar lineNumber: 7, memberName: "class Bar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target2", relationship: InheritanceRelationship.ImplementedInterface))); @@ -486,7 +509,7 @@ public class {|target1:Bar|} : IBar lineNumber: 5, memberName: "event EventHandler IBar.e", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "event EventHandler Bar.e", + targetSymbolDisplayName: "Bar.e", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember))); @@ -494,7 +517,7 @@ public class {|target1:Bar|} : IBar lineNumber: 9, memberName: "event EventHandler Bar.e", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "event EventHandler IBar.e", + targetSymbolDisplayName: "IBar.e", locationTag: "target4", relationship: InheritanceRelationship.ImplementedMember))); @@ -523,7 +546,7 @@ public class {|target1:Bar|} : IBar lineNumber: 2, memberName: "interface IBar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -531,7 +554,7 @@ public class {|target1:Bar|} : IBar lineNumber: 6, memberName: "class Bar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target2", relationship: InheritanceRelationship.ImplementedInterface))); @@ -539,7 +562,7 @@ public class {|target1:Bar|} : IBar lineNumber: 4, memberName: "event EventHandler IBar.e1", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "event EventHandler Bar.e1", + targetSymbolDisplayName: "Bar.e1", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember))); @@ -547,7 +570,7 @@ public class {|target1:Bar|} : IBar lineNumber: 4, memberName: "event EventHandler IBar.e2", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "event EventHandler Bar.e2", + targetSymbolDisplayName: "Bar.e2", locationTag: "target4", relationship: InheritanceRelationship.ImplementingMember))); @@ -555,7 +578,7 @@ public class {|target1:Bar|} : IBar lineNumber: 8, memberName: "event EventHandler Bar.e1", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "event EventHandler IBar.e1", + targetSymbolDisplayName: "IBar.e1", locationTag: "target5", relationship: InheritanceRelationship.ImplementedMember))); @@ -563,7 +586,7 @@ public class {|target1:Bar|} : IBar lineNumber: 8, memberName: "event EventHandler Bar.e2", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "event EventHandler IBar.e2", + targetSymbolDisplayName: "IBar.e2", locationTag: "target6", relationship: InheritanceRelationship.ImplementedMember))); @@ -600,7 +623,7 @@ public class {|target2:Bar|} : IBar lineNumber: 13, memberName: "event EventHandler Bar.Eoo", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "event EventHandler IBar.Eoo", + targetSymbolDisplayName: "IBar.Eoo", locationTag: "target8", relationship: InheritanceRelationship.ImplementedMember)) ); @@ -609,7 +632,7 @@ public class {|target2:Bar|} : IBar lineNumber: 6, memberName: "event EventHandler IBar.Eoo", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "event EventHandler Bar.Eoo", + targetSymbolDisplayName: "Bar.Eoo", locationTag: "target7", relationship: InheritanceRelationship.ImplementingMember)) ); @@ -618,7 +641,7 @@ public class {|target2:Bar|} : IBar lineNumber: 5, memberName: "int IBar.Poo { get; set; }", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "int Bar.Poo { get; set; }", + targetSymbolDisplayName: "Bar.Poo", locationTag: "target5", relationship: InheritanceRelationship.ImplementingMember)) ); @@ -627,7 +650,7 @@ public class {|target2:Bar|} : IBar lineNumber: 12, memberName: "int Bar.Poo { get; set; }", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "int IBar.Poo { get; set; }", + targetSymbolDisplayName: "IBar.Poo", locationTag: "target6", relationship: InheritanceRelationship.ImplementedMember)) ); @@ -636,7 +659,7 @@ public class {|target2:Bar|} : IBar lineNumber: 4, memberName: "void IBar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void Bar.Foo()", + targetSymbolDisplayName: "Bar.Foo", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember)) ); @@ -645,7 +668,7 @@ public class {|target2:Bar|} : IBar lineNumber: 11, memberName: "void Bar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void IBar.Foo()", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target4", relationship: InheritanceRelationship.ImplementedMember)) ); @@ -654,7 +677,7 @@ public class {|target2:Bar|} : IBar lineNumber: 2, memberName: "interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target2", relationship: InheritanceRelationship.ImplementingType)) ); @@ -663,7 +686,7 @@ public class {|target2:Bar|} : IBar lineNumber: 9, memberName: "class Bar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target1", relationship: InheritanceRelationship.ImplementedInterface)) ); @@ -672,7 +695,7 @@ public class {|target2:Bar|} : IBar lineNumber: 14, memberName: "int Bar.this[int] { get; set; }", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "int IBar.this[int] { get; set; }", + targetSymbolDisplayName: "IBar.this", locationTag: "target9", relationship: InheritanceRelationship.ImplementedMember)) ); @@ -681,7 +704,7 @@ public class {|target2:Bar|} : IBar lineNumber: 7, memberName: "int IBar.this[int] { get; set; }", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "int Bar.this[int] { get; set; }", + targetSymbolDisplayName: "Bar.this", locationTag: "target10", relationship: InheritanceRelationship.ImplementingMember)) ); @@ -725,7 +748,7 @@ public class {{|target1:Bar2|}} : Bar lineNumber: 12, memberName: "override event EventHandler Bar2.Eoo", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: $"{modifier} event EventHandler Bar.Eoo", + targetSymbolDisplayName: $"Bar.Eoo", locationTag: "target8", relationship: InheritanceRelationship.OverriddenMember))); @@ -733,7 +756,7 @@ public class {{|target1:Bar2|}} : Bar lineNumber: 6, memberName: $"{modifier} event EventHandler Bar.Eoo", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "override event EventHandler Bar2.Eoo", + targetSymbolDisplayName: "Bar2.Eoo", locationTag: "target7", relationship: InheritanceRelationship.OverridingMember))); @@ -741,7 +764,7 @@ public class {{|target1:Bar2|}} : Bar lineNumber: 11, memberName: "override int Bar2.Poo { get; set; }", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: $"{modifier} int Bar.Poo {{ get; set; }}", + targetSymbolDisplayName: $"Bar.Poo", locationTag: "target6", relationship: InheritanceRelationship.OverriddenMember))); @@ -749,7 +772,7 @@ public class {{|target1:Bar2|}} : Bar lineNumber: 5, memberName: $"{modifier} int Bar.Poo {{ get; set; }}", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "override int Bar2.Poo { get; set; }", + targetSymbolDisplayName: "Bar2.Poo", locationTag: "target5", relationship: InheritanceRelationship.OverridingMember))); @@ -757,7 +780,7 @@ public class {{|target1:Bar2|}} : Bar lineNumber: 4, memberName: $"{modifier} void Bar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "override void Bar2.Foo()", + targetSymbolDisplayName: "Bar2.Foo", locationTag: "target3", relationship: InheritanceRelationship.OverridingMember))); @@ -765,7 +788,7 @@ public class {{|target1:Bar2|}} : Bar lineNumber: 10, memberName: "override void Bar2.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: $"{modifier} void Bar.Foo()", + targetSymbolDisplayName: $"Bar.Foo", locationTag: "target4", relationship: InheritanceRelationship.OverriddenMember))); @@ -773,7 +796,7 @@ public class {{|target1:Bar2|}} : Bar lineNumber: 2, memberName: "class Bar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Bar2", + targetSymbolDisplayName: "Bar2", locationTag: "target1", relationship: InheritanceRelationship.DerivedType))); @@ -781,7 +804,7 @@ public class {{|target1:Bar2|}} : Bar lineNumber: 8, memberName: "class Bar2", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target2", relationship: InheritanceRelationship.BaseType))); @@ -834,11 +857,11 @@ public class {|target5:Bar2|} : Bar1, IBar lineNumber: 2, memberName: "interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Bar1", + targetSymbolDisplayName: "Bar1", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType), new TargetInfo( - targetSymbolDisplayName: "class Bar2", + targetSymbolDisplayName: "Bar2", locationTag: "target5", relationship: InheritanceRelationship.ImplementingType))); @@ -846,11 +869,11 @@ public class {|target5:Bar2|} : Bar1, IBar lineNumber: 4, memberName: "void IBar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "virtual void Bar1.Foo()", + targetSymbolDisplayName: "Bar1.Foo", locationTag: "target2", relationship: InheritanceRelationship.ImplementingMember), new TargetInfo( - targetSymbolDisplayName: "override void Bar2.Foo()", + targetSymbolDisplayName: "Bar2.Foo", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember))); @@ -858,11 +881,11 @@ public class {|target5:Bar2|} : Bar1, IBar lineNumber: 6, memberName: "class Bar1", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target4", relationship: InheritanceRelationship.ImplementedInterface), new TargetInfo( - targetSymbolDisplayName: "class Bar2", + targetSymbolDisplayName: "Bar2", locationTag: "target5", relationship: InheritanceRelationship.DerivedType))); @@ -870,11 +893,11 @@ public class {|target5:Bar2|} : Bar1, IBar lineNumber: 8, memberName: "virtual void Bar1.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void IBar.Foo()", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target6", relationship: InheritanceRelationship.ImplementedMember), new TargetInfo( - targetSymbolDisplayName: "override void Bar2.Foo()", + targetSymbolDisplayName: "Bar2.Foo", locationTag: "target3", relationship: InheritanceRelationship.OverridingMember))); @@ -883,11 +906,11 @@ public class {|target5:Bar2|} : Bar1, IBar memberName: "class Bar2", targets: ImmutableArray.Create( new TargetInfo( - targetSymbolDisplayName: "class Bar1", + targetSymbolDisplayName: "Bar1", locationTag: "target1", relationship: InheritanceRelationship.BaseType), new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target4", relationship: InheritanceRelationship.ImplementedInterface))); @@ -895,11 +918,11 @@ public class {|target5:Bar2|} : Bar1, IBar lineNumber: 12, memberName: "override void Bar2.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void IBar.Foo()", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target6", relationship: InheritanceRelationship.ImplementedMember), new TargetInfo( - targetSymbolDisplayName: "virtual void Bar1.Foo()", + targetSymbolDisplayName: "Bar1.Foo", locationTag: "target2", relationship: InheritanceRelationship.OverriddenMember))); @@ -932,7 +955,7 @@ public class {|target1:Bar2|} : IBar, IBar lineNumber: 2, memberName: "interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Bar2", + targetSymbolDisplayName: "Bar2", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -940,7 +963,7 @@ public class {|target1:Bar2|} : IBar, IBar lineNumber: 4, memberName: "void IBar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void Bar2.Foo()", + targetSymbolDisplayName: "Bar2.Foo", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember))); @@ -949,7 +972,7 @@ public class {|target1:Bar2|} : IBar, IBar lineNumber: 7, memberName: "class Bar2", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target2", relationship: InheritanceRelationship.ImplementedInterface))); @@ -958,7 +981,7 @@ public class {|target1:Bar2|} : IBar, IBar lineNumber: 9, memberName: "void Bar2.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void IBar.Foo()", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target4", relationship: InheritanceRelationship.ImplementedMember))); @@ -991,7 +1014,7 @@ abstract class {|target1:AbsBar|} : IBar lineNumber: 2, memberName: "interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class AbsBar", + targetSymbolDisplayName: "AbsBar", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -999,7 +1022,7 @@ abstract class {|target1:AbsBar|} : IBar lineNumber: 4, memberName: "void IBar.Foo(T)", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void AbsBar.IBar.Foo(int)", + targetSymbolDisplayName: "AbsBar.IBar.Foo", locationTag: "target4", relationship: InheritanceRelationship.ImplementingMember))); @@ -1007,7 +1030,7 @@ abstract class {|target1:AbsBar|} : IBar lineNumber: 7, memberName: "class AbsBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target2", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1015,7 +1038,7 @@ abstract class {|target1:AbsBar|} : IBar lineNumber: 9, memberName: "void AbsBar.IBar.Foo(int)", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void IBar.Foo(T)", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target3", relationship: InheritanceRelationship.ImplementedMember) )); @@ -1054,7 +1077,7 @@ public class {|target1:Class1|} : I1 lineNumber: 2, memberName: "interface I1", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Class1", + targetSymbolDisplayName: "Class1", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -1062,7 +1085,7 @@ public class {|target1:Class1|} : I1 lineNumber: 4, memberName: "void I1.M1()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "static void Class1.M1()", + targetSymbolDisplayName: "Class1.M1", locationTag: "target2", relationship: InheritanceRelationship.ImplementingMember))); @@ -1070,7 +1093,7 @@ public class {|target1:Class1|} : I1 lineNumber: 11, memberName: "class Class1", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface I1", + targetSymbolDisplayName: "I1", locationTag: "target5", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1078,7 +1101,7 @@ public class {|target1:Class1|} : I1 lineNumber: 13, memberName: "static void Class1.M1()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void I1.M1()", + targetSymbolDisplayName: "I1.M1", locationTag: "target4", relationship: InheritanceRelationship.ImplementedMember))); @@ -1086,7 +1109,7 @@ public class {|target1:Class1|} : I1 lineNumber: 5, memberName: "int I1.P1 { get; set; }", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "static int Class1.P1 { get; set; }", + targetSymbolDisplayName: "Class1.P1", locationTag: "target6", relationship: InheritanceRelationship.ImplementingMember))); @@ -1094,7 +1117,7 @@ public class {|target1:Class1|} : I1 lineNumber: 14, memberName: "static int Class1.P1 { get; set; }", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "int I1.P1 { get; set; }", + targetSymbolDisplayName: "I1.P1", locationTag: "target7", relationship: InheritanceRelationship.ImplementedMember))); @@ -1102,7 +1125,7 @@ public class {|target1:Class1|} : I1 lineNumber: 6, memberName: "event EventHandler I1.e1", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "static event EventHandler Class1.e1", + targetSymbolDisplayName: "Class1.e1", locationTag: "target8", relationship: InheritanceRelationship.ImplementingMember))); @@ -1110,7 +1133,7 @@ public class {|target1:Class1|} : I1 lineNumber: 15, memberName: "static event EventHandler Class1.e1", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "event EventHandler I1.e1", + targetSymbolDisplayName: "I1.e1", locationTag: "target9", relationship: InheritanceRelationship.ImplementedMember))); @@ -1118,7 +1141,7 @@ public class {|target1:Class1|} : I1 lineNumber: 7, memberName: "int I1.operator +(T)", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "static int Class1.operator +(Class1)", + targetSymbolDisplayName: "Class1.operator +", locationTag: "target10", relationship: InheritanceRelationship.ImplementingMember))); @@ -1126,7 +1149,7 @@ public class {|target1:Class1|} : I1 lineNumber: 16, memberName: "static int Class1.operator +(Class1)", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "int I1.operator +(T)", + targetSymbolDisplayName: "I1.operator +", locationTag: "target11", relationship: InheritanceRelationship.ImplementedMember))); @@ -1134,7 +1157,7 @@ public class {|target1:Class1|} : I1 lineNumber: 8, memberName: "I1.implicit operator int(T)", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "static Class1.implicit operator int(Class1)", + targetSymbolDisplayName: "Class1.implicit operator int", locationTag: "target13", relationship: InheritanceRelationship.ImplementingMember))); @@ -1142,7 +1165,7 @@ public class {|target1:Class1|} : I1 lineNumber: 17, memberName: "static Class1.implicit operator int(Class1)", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "I1.implicit operator int(T)", + targetSymbolDisplayName: "I1.implicit operator int", locationTag: "target12", relationship: InheritanceRelationship.ImplementedMember))); @@ -1163,6 +1186,55 @@ public class {|target1:Class1|} : I1 itemForIntOperatorInClass1); } + [Fact] + public Task TestCSharpPartialClass() + { + var markup = @" +interface {|target1:IBar|} +{ +} + +public partial class {|target2:Bar|} : IBar +{ +} + +public partial class {|target3:Bar|} +{ +} + "; + + var itemOnLine2 = new TestInheritanceMemberItem( + lineNumber: 2, + memberName: "interface IBar", + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "Bar", + relationship: InheritanceRelationship.ImplementingType, + "target2", "target3"))); + + var itemOnLine6 = new TestInheritanceMemberItem( + lineNumber: 6, + memberName: "class Bar", + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "IBar", + locationTag: "target1", + relationship: InheritanceRelationship.ImplementedInterface))); + + var itemOnLine10 = new TestInheritanceMemberItem( + lineNumber: 10, + memberName: "class Bar", + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "IBar", + locationTag: "target1", + relationship: InheritanceRelationship.ImplementedInterface))); + + return VerifyInSingleDocumentAsync( + markup, + LanguageNames.CSharp, + itemOnLine2, + itemOnLine6, + itemOnLine10); + } + #endregion #region TestsForVisualBasic @@ -1196,7 +1268,7 @@ End Class lineNumber: 3, memberName: "Class Bar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IEnumerable", + targetSymbolDisplayName: "IEnumerable", relationship: InheritanceRelationship.ImplementedInterface, inMetadata: true))); @@ -1204,7 +1276,7 @@ End Class lineNumber: 5, memberName: "Function Bar.GetEnumerator() As IEnumerator", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Function IEnumerable.GetEnumerator() As IEnumerator", + targetSymbolDisplayName: "IEnumerable.GetEnumerator", relationship: InheritanceRelationship.ImplementedMember, inMetadata: true))); @@ -1224,7 +1296,7 @@ Implements IBar lineNumber: 2, memberName: "Interface IBar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -1232,7 +1304,7 @@ Implements IBar lineNumber: 4, memberName: "Class Bar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target2", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1257,7 +1329,7 @@ Inherits IBar2 lineNumber: 2, memberName: "Interface IBar2", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -1265,7 +1337,7 @@ Inherits IBar2 lineNumber: 4, memberName: "Interface IBar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IBar2", + targetSymbolDisplayName: "IBar2", locationTag: "target2", relationship: InheritanceRelationship.InheritedInterface))); return VerifyInSingleDocumentAsync(markup, LanguageNames.VisualBasic, itemForIBar2, itemForIBar); @@ -1285,7 +1357,7 @@ Inherits Bar2 lineNumber: 2, memberName: "Class Bar2", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target1", relationship: InheritanceRelationship.DerivedType))); @@ -1293,7 +1365,7 @@ Inherits Bar2 lineNumber: 4, memberName: "Class Bar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar2", + targetSymbolDisplayName: "Bar2", locationTag: "target2", relationship: InheritanceRelationship.BaseType))); return VerifyInSingleDocumentAsync(markup, LanguageNames.VisualBasic, itemForBar2, itemForBar); @@ -1329,7 +1401,7 @@ Implements IEnumerable memberName: "Class Bar", targets: ImmutableArray.Create( new TargetInfo( - targetSymbolDisplayName: "Interface IEnumerable", + targetSymbolDisplayName: "IEnumerable", relationship: InheritanceRelationship.ImplementedInterface, inMetadata: true)))); } @@ -1350,7 +1422,7 @@ Implements IBar lineNumber: 2, memberName: "Interface IBar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -1358,7 +1430,7 @@ Implements IBar lineNumber: 5, memberName: "Class Bar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target2", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1366,7 +1438,7 @@ Implements IBar lineNumber: 3, memberName: "Event IBar.e As EventHandler", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Event Bar.e As EventHandler", + targetSymbolDisplayName: "Bar.e", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember))); @@ -1374,7 +1446,7 @@ Implements IBar lineNumber: 7, memberName: "Event Bar.e As EventHandler", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Event IBar.e As EventHandler", + targetSymbolDisplayName: "IBar.e", locationTag: "target4", relationship: InheritanceRelationship.ImplementedMember))); @@ -1403,7 +1475,7 @@ End Event lineNumber: 2, memberName: "Interface IBar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -1411,7 +1483,7 @@ End Event lineNumber: 5, memberName: "Class Bar", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target2", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1419,7 +1491,7 @@ End Event lineNumber: 3, memberName: "Event IBar.e As EventHandler", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Event Bar.e As EventHandler", + targetSymbolDisplayName: "Bar.e", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember))); @@ -1427,7 +1499,7 @@ End Event lineNumber: 7, memberName: "Event Bar.e As EventHandler", ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Event IBar.e As EventHandler", + targetSymbolDisplayName: "IBar.e", locationTag: "target4", relationship: InheritanceRelationship.ImplementedMember))); @@ -1466,7 +1538,7 @@ End Function lineNumber: 2, memberName: "Interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -1474,7 +1546,7 @@ End Function lineNumber: 7, memberName: "Class Bar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target2", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1482,7 +1554,7 @@ End Function lineNumber: 3, memberName: "Property IBar.Poo As Integer", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Property Bar.Poo As Integer", + targetSymbolDisplayName: "Bar.Poo", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember))); @@ -1490,7 +1562,7 @@ End Function lineNumber: 9, memberName: "Property Bar.Poo As Integer", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Property IBar.Poo As Integer", + targetSymbolDisplayName: "IBar.Poo", locationTag: "target4", relationship: InheritanceRelationship.ImplementedMember))); @@ -1498,7 +1570,7 @@ End Function lineNumber: 4, memberName: "Function IBar.Foo() As Integer", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Function Bar.Foo() As Integer", + targetSymbolDisplayName: "Bar.Foo", locationTag: "target5", relationship: InheritanceRelationship.ImplementingMember))); @@ -1506,7 +1578,7 @@ End Function lineNumber: 16, memberName: "Function Bar.Foo() As Integer", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Function IBar.Foo() As Integer", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target6", relationship: InheritanceRelationship.ImplementedMember))); @@ -1538,7 +1610,7 @@ End Sub lineNumber: 2, memberName: "Class Bar1", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: $"Class Bar", + targetSymbolDisplayName: $"Bar", locationTag: "target1", relationship: InheritanceRelationship.DerivedType))); @@ -1546,7 +1618,7 @@ End Sub lineNumber: 6, memberName: "Class Bar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar1", + targetSymbolDisplayName: "Bar1", locationTag: "target2", relationship: InheritanceRelationship.BaseType))); @@ -1554,7 +1626,7 @@ End Sub lineNumber: 3, memberName: "MustOverride Sub Bar1.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Overrides Sub Bar.Foo()", + targetSymbolDisplayName: "Bar.Foo", locationTag: "target3", relationship: InheritanceRelationship.OverridingMember))); @@ -1562,7 +1634,7 @@ End Sub lineNumber: 8, memberName: "Overrides Sub Bar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "MustOverride Sub Bar1.Foo()", + targetSymbolDisplayName: "Bar1.Foo", locationTag: "target4", relationship: InheritanceRelationship.OverriddenMember))); @@ -1616,47 +1688,49 @@ End Sub lineNumber: 2, memberName: "Interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar1", + targetSymbolDisplayName: "Bar1", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType), - new TargetInfo( - targetSymbolDisplayName: "Class Bar2", - locationTag: "target5", - relationship: InheritanceRelationship.ImplementingType))); + new TargetInfo( + targetSymbolDisplayName: "Bar2", + locationTag: "target5", + relationship: InheritanceRelationship.ImplementingType))); var itemForFooInIBar = new TestInheritanceMemberItem( lineNumber: 3, memberName: "Sub IBar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Overridable Sub Bar1.Foo()", + targetSymbolDisplayName: "Bar1.Foo", locationTag: "target2", relationship: InheritanceRelationship.ImplementingMember), new TargetInfo( - targetSymbolDisplayName: "Overrides Sub Bar2.Foo()", + targetSymbolDisplayName: "Bar2.Foo", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember))); var itemForBar1 = new TestInheritanceMemberItem( lineNumber: 6, memberName: "Class Bar1", - targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IBar", - locationTag: "target4", - relationship: InheritanceRelationship.ImplementedInterface), + targets: ImmutableArray.Create( new TargetInfo( - targetSymbolDisplayName: "Class Bar2", + targetSymbolDisplayName: "Bar2", locationTag: "target5", - relationship: InheritanceRelationship.DerivedType))); + relationship: InheritanceRelationship.DerivedType), + new TargetInfo( + targetSymbolDisplayName: "IBar", + locationTag: "target4", + relationship: InheritanceRelationship.ImplementedInterface) + )); var itemForFooInBar1 = new TestInheritanceMemberItem( lineNumber: 8, memberName: "Overridable Sub Bar1.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Sub IBar.Foo()", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target6", relationship: InheritanceRelationship.ImplementedMember), new TargetInfo( - targetSymbolDisplayName: "Overrides Sub Bar2.Foo()", + targetSymbolDisplayName: "Bar2.Foo", locationTag: "target3", relationship: InheritanceRelationship.OverridingMember))); @@ -1665,11 +1739,11 @@ End Sub memberName: "Class Bar2", targets: ImmutableArray.Create( new TargetInfo( - targetSymbolDisplayName: "Class Bar1", + targetSymbolDisplayName: "Bar1", locationTag: "target1", relationship: InheritanceRelationship.BaseType), new TargetInfo( - targetSymbolDisplayName: "Interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target4", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1677,11 +1751,11 @@ End Sub lineNumber: 14, memberName: "Overrides Sub Bar2.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Sub IBar.Foo()", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target6", relationship: InheritanceRelationship.ImplementedMember), new TargetInfo( - targetSymbolDisplayName: "Overridable Sub Bar1.Foo()", + targetSymbolDisplayName: "Bar1.Foo", locationTag: "target2", relationship: InheritanceRelationship.OverriddenMember))); @@ -1721,7 +1795,7 @@ End Sub lineNumber: 2, memberName: "Interface IBar(Of T)", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target1", relationship: InheritanceRelationship.ImplementingType))); @@ -1729,11 +1803,11 @@ End Sub lineNumber: 3, memberName: "Sub IBar(Of T).Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Sub Bar.Foo()", + targetSymbolDisplayName: "Bar.Foo", locationTag: "target3", relationship: InheritanceRelationship.ImplementingMember), new TargetInfo( - targetSymbolDisplayName: "Sub Bar.IBar_Foo()", + targetSymbolDisplayName: "Bar.IBar_Foo", locationTag: "target4", relationship: InheritanceRelationship.ImplementingMember))); @@ -1741,7 +1815,7 @@ End Sub lineNumber: 6, memberName: "Class Bar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IBar(Of T)", + targetSymbolDisplayName: "IBar(Of T)", locationTag: "target5", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1749,7 +1823,7 @@ End Sub lineNumber: 10, memberName: "Sub Bar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Sub IBar(Of T).Foo()", + targetSymbolDisplayName: "IBar(Of T).Foo", locationTag: "target6", relationship: InheritanceRelationship.ImplementedMember))); @@ -1757,7 +1831,7 @@ End Sub lineNumber: 14, memberName: "Sub Bar.IBar_Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Sub IBar(Of T).Foo()", + targetSymbolDisplayName: "IBar(Of T).Foo", locationTag: "target6", relationship: InheritanceRelationship.ImplementedMember))); @@ -1797,7 +1871,7 @@ End Interface lineNumber: 5, memberName: "class Bar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target1", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1805,7 +1879,7 @@ End Interface lineNumber: 7, memberName: "void Bar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Sub IBar.Foo()", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target3", relationship: InheritanceRelationship.ImplementedMember))); @@ -1813,7 +1887,7 @@ End Interface lineNumber: 3, memberName: "Interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "class Bar", + targetSymbolDisplayName: "Bar", locationTag: "target2", relationship: InheritanceRelationship.ImplementingType))); @@ -1821,7 +1895,7 @@ End Interface lineNumber: 4, memberName: "Sub IBar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void Bar.Foo()", + targetSymbolDisplayName: "Bar.Foo", locationTag: "target4", relationship: InheritanceRelationship.ImplementingMember))); @@ -1859,7 +1933,7 @@ public interface {|target1:IBar|} lineNumber: 4, memberName: "Class Bar44", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "interface IBar", + targetSymbolDisplayName: "IBar", locationTag: "target1", relationship: InheritanceRelationship.ImplementedInterface))); @@ -1867,7 +1941,7 @@ public interface {|target1:IBar|} lineNumber: 7, memberName: "Sub Bar44.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "void IBar.Foo()", + targetSymbolDisplayName: "IBar.Foo", locationTag: "target3", relationship: InheritanceRelationship.ImplementedMember))); @@ -1875,7 +1949,7 @@ public interface {|target1:IBar|} lineNumber: 4, memberName: "interface IBar", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Class Bar44", + targetSymbolDisplayName: "Bar44", locationTag: "target2", relationship: InheritanceRelationship.ImplementingType))); @@ -1883,7 +1957,7 @@ public interface {|target1:IBar|} lineNumber: 6, memberName: "void IBar.Foo()", targets: ImmutableArray.Create(new TargetInfo( - targetSymbolDisplayName: "Sub Bar44.Foo()", + targetSymbolDisplayName: "Bar44.Foo", locationTag: "target4", relationship: InheritanceRelationship.ImplementingMember))); diff --git a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs index 0a896f1090385..bbeeeda18e349 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs @@ -20,6 +20,8 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.MetadataAsSource [UseExportProvider] public abstract partial class AbstractMetadataAsSourceTests : IAsyncLifetime { + protected static readonly string ICSharpCodeDecompilerVersion = "7.1.0.6543"; + public virtual Task InitializeAsync() { AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.MscorlibRef_v46, "mscorlib.v4_6_1038_0.dll", ImmutableArray.Create(TestMetadata.ResourcesNet461.mscorlib)); diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs index 928cfa0c8fad1..a2c690b4be570 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs @@ -55,7 +55,7 @@ public class [|C|] }}", false => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] @@ -101,16 +101,12 @@ public class [|C|] }}", false => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] {{ - public int Property - {{ - get; - set; - }} + public int Property {{ get; init; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 6)} @@ -147,7 +143,7 @@ public class [|C|] }}", false => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] @@ -205,7 +201,7 @@ public struct [|ValueTuple|] : IEquatable, IStructuralEquatable, ISt }}", false => $@"#region {FeaturesResources.Assembly} System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 // System.ValueTuple.dll -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Collections; @@ -428,7 +424,7 @@ public class [|C|] }}", false => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.VisualBasic.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.VisualBasic.cs index 64df3aad5209d..6da215dc63320 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.VisualBasic.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.VisualBasic.cs @@ -39,7 +39,7 @@ End Class End Module", false => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using Microsoft.VisualBasic.CompilerServices; @@ -98,7 +98,7 @@ End Class End Namespace", false => $@"#region {FeaturesResources.Assembly} mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -260,7 +260,7 @@ End Structure End Namespace", false => $@"#region {FeaturesResources.Assembly} System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Collections; diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs index bb5b7a0f82215..155571422b518 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs @@ -61,7 +61,7 @@ Public Sub New() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] @@ -76,7 +76,7 @@ public class [|C|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] @@ -119,7 +119,7 @@ Public Interface [|I|] End Interface", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public interface [|I|] @@ -134,7 +134,7 @@ public interface [|I|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public interface [|I|] @@ -178,7 +178,7 @@ Public Class C End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] @@ -193,7 +193,7 @@ public class [|C|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] @@ -241,7 +241,7 @@ Public Sub New() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -259,7 +259,7 @@ public class C #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -310,7 +310,7 @@ Public Sub New() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -326,7 +326,7 @@ public class C #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -376,16 +376,12 @@ Public Property [|S|] As String End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C {{ - public string [|S|] - {{ - get; - protected set; - }} + public string [|S|] {{ get; protected set; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 6)} @@ -396,16 +392,12 @@ public string [|S|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C {{ - public string [|S|] - {{ - get; - protected set; - }} + public string [|S|] {{ get; protected set; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 9)} @@ -455,7 +447,7 @@ Public Event [|E|] As Action End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -473,7 +465,7 @@ public class C #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -529,7 +521,7 @@ End Class End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -547,7 +539,7 @@ protected class [|D|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -599,7 +591,7 @@ Public Enum [|E|] End Enum", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum [|E|] @@ -617,7 +609,7 @@ public enum [|E|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum [|E|] @@ -669,7 +661,7 @@ Public Enum E End Enum", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum E @@ -687,7 +679,7 @@ public enum E #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum E @@ -739,7 +731,7 @@ Public Enum E As Short End Enum", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum E : short @@ -757,7 +749,7 @@ public enum E : short #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum E : short @@ -805,7 +797,7 @@ Public Enum E As ULong End Enum", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum E : ulong @@ -821,7 +813,7 @@ public enum E : ulong #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum E : ulong @@ -870,7 +862,7 @@ Public Enum E As Short End Enum", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum E : short @@ -888,7 +880,7 @@ public enum E : short #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public enum E : short @@ -941,7 +933,7 @@ End Class End Namespace", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion namespace N @@ -959,7 +951,7 @@ public class [|C|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion namespace N @@ -1091,7 +1083,7 @@ Public Sub New() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -1107,7 +1099,7 @@ public class C #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -1165,7 +1157,7 @@ Public Sub New() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion [MyType(typeof(string))] @@ -1181,7 +1173,7 @@ public class [|C|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion [MyType(typeof(string))] @@ -1225,7 +1217,7 @@ Public Structure [|S|] End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -1243,7 +1235,7 @@ public struct [|S|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -1294,7 +1286,7 @@ Public Shared Function Create() As C End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] @@ -1313,7 +1305,7 @@ public static C Create() #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|] @@ -1366,7 +1358,7 @@ Public Sub New() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|G|] @@ -1382,7 +1374,7 @@ public class [|G|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|G|] @@ -1439,7 +1431,7 @@ Public Sub Method( x As T, y As T) End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|]<[My] T> @@ -1457,7 +1449,7 @@ public void Method([My] T x, [My] T y) #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|C|]<[My] T> @@ -1515,7 +1507,7 @@ Function Equals( other As T) As Boolean End Interface", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public interface [|C|] @@ -1531,7 +1523,7 @@ public interface [|C|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public interface [|C|] @@ -1580,7 +1572,7 @@ Public Sub New() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -1596,7 +1588,7 @@ public class C #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class C @@ -1661,7 +1653,7 @@ Public Sub New() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using N; @@ -1679,7 +1671,7 @@ public class [|C|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using N; @@ -1986,7 +1978,7 @@ Protected Overrides Sub Finalize() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -2000,11 +1992,7 @@ public class [|C|] public int field1; [Obsolete] - public int prop1 - {{ - get; - set; - }} + public int prop1 {{ get; set; }} [Obsolete] public int prop2 @@ -2078,7 +2066,7 @@ public void method2([CallerMemberName] string name = """") #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -2092,11 +2080,7 @@ public class [|C|] public int field1; [Obsolete] - public int prop1 - {{ - get; - set; - }} + public int prop1 {{ get; set; }} [Obsolete] public int prop2 @@ -2264,7 +2248,7 @@ Protected Overrides Sub Finalize() End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -2276,11 +2260,7 @@ public class [|C|] public int field2; - public int prop1 - {{ - get; - set; - }} + public int prop1 {{ get; set; }} public int prop2 {{ @@ -2347,7 +2327,7 @@ public void method2([CallerMemberName] string name = """") #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -2359,11 +2339,7 @@ public class [|C|] public int field2; - public int prop1 - {{ - get; - set; - }} + public int prop1 {{ get; set; }} public int prop2 {{ @@ -2497,18 +2473,14 @@ Function Method1() As Uri End Interface", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; public interface [|IGoo|] {{ - Uri Prop1 - {{ - get; - set; - }} + Uri Prop1 {{ get; set; }} Uri Method1(); }} @@ -2525,18 +2497,14 @@ Uri Prop1 #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; public interface [|IGoo|] {{ - Uri Prop1 - {{ - get; - set; - }} + Uri Prop1 {{ get; set; }} Uri Method1(); }} @@ -2598,7 +2566,7 @@ Public Sub goo(Optional options As FileOptions = FileOptions.None) End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.IO; @@ -2618,7 +2586,7 @@ public void goo(FileOptions options = FileOptions.None) #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.IO; @@ -2685,7 +2653,7 @@ Public Sub New(i() As Integer) End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -2706,7 +2674,7 @@ public TestAttribute(int[] i) #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -2867,7 +2835,7 @@ Default Public Property Item(x As Integer) As Integer End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|Program|] @@ -2897,7 +2865,7 @@ public int this[int x] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public class [|Program|] @@ -2982,7 +2950,7 @@ Sub MOverload(i As Integer) End Interface", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -2991,10 +2959,7 @@ Sub MOverload(i As Integer) [Guid(""666A175D-2448-447A-B786-CCC82CBEF156"")] public interface [|IComImport|] {{ - int Prop - {{ - get; - }} + int Prop {{ get; }} void MOverload(); @@ -3011,7 +2976,7 @@ int Prop #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -3020,10 +2985,7 @@ int Prop [Guid(""666A175D-2448-447A-B786-CCC82CBEF156"")] public interface [|IComImport|] {{ - int Prop - {{ - get; - }} + int Prop {{ get; }} void MOverload(); @@ -3082,7 +3044,7 @@ Public Sub M(Optional cancellationToken As CancellationToken = Nothing) End Class", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Threading; @@ -3102,7 +3064,7 @@ public class [|C|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Threading; @@ -3196,18 +3158,14 @@ Function Method1() As Uri End Interface", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; public interface [|IGoo|] {{ - Uri Prop1 - {{ - get; - set; - }} + Uri Prop1 {{ get; set; }} Uri Method1(); }} @@ -3224,18 +3182,14 @@ Uri Prop1 #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; public interface [|IGoo|] {{ - Uri Prop1 - {{ - get; - set; - }} + Uri Prop1 {{ get; set; }} Uri Method1(); }} @@ -3509,7 +3463,7 @@ Public ReadOnly i As Integer End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public readonly struct [|S|] @@ -3525,7 +3479,7 @@ public readonly struct [|S|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public readonly struct [|S|] @@ -3576,7 +3530,7 @@ Public ReadOnly i As Integer End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public struct [|S|] @@ -3592,7 +3546,7 @@ public struct [|S|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public struct [|S|] @@ -3643,7 +3597,7 @@ Public Structure [|S|] End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -3661,7 +3615,7 @@ public ref struct [|S|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -3714,7 +3668,7 @@ Public Structure [|S|] End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -3732,7 +3686,7 @@ public readonly ref struct [|S|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -3786,7 +3740,7 @@ Public Structure S End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -3807,7 +3761,7 @@ public struct S #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -3865,7 +3819,7 @@ Public Structure S End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -3886,7 +3840,7 @@ public readonly struct S #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -3942,15 +3896,12 @@ Public ReadOnly Property [|P|] As Integer End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public struct S {{ - public int [|P|] - {{ - get; - }} + public int [|P|] {{ get; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 6)} @@ -3961,15 +3912,12 @@ public int [|P|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public struct S {{ - public int [|P|] - {{ - get; - }} + public int [|P|] {{ get; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 9)} @@ -4015,15 +3963,12 @@ Public ReadOnly Property [|P|] As Integer End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public struct S {{ - public int [|P|] - {{ - get; - }} + public int [|P|] {{ get; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 6)} @@ -4034,15 +3979,12 @@ public int [|P|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public struct S {{ - public int [|P|] - {{ - get; - }} + public int [|P|] {{ get; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 9)} @@ -4095,15 +4037,12 @@ Public ReadOnly Property [|P|] As Integer End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public struct S {{ - public int [|P|] - {{ - get; - }} + public int [|P|] {{ get; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 6)} @@ -4114,15 +4053,12 @@ public int [|P|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public struct S {{ - public int [|P|] - {{ - get; - }} + public int [|P|] {{ get; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 9)} @@ -4170,15 +4106,12 @@ Public ReadOnly Property [|P|] As Integer End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public readonly struct S {{ - public int [|P|] - {{ - get; - }} + public int [|P|] {{ get; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 6)} @@ -4189,15 +4122,12 @@ public int [|P|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion public readonly struct S {{ - public int [|P|] - {{ - get; - }} + public int [|P|] {{ get; }} }} #if false // {CSharpEditorResources.Decompilation_log} {string.Format(CSharpEditorResources._0_items_in_cache, 9)} @@ -4243,7 +4173,7 @@ Public Property [|P|] As Integer End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4271,7 +4201,7 @@ readonly get #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4334,7 +4264,7 @@ Public Property [|P|] As Integer End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4362,7 +4292,7 @@ readonly set #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4425,7 +4355,7 @@ Public Property [|P|] As Integer End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4453,7 +4383,7 @@ public readonly int [|P|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4522,7 +4452,7 @@ Public Structure S End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4541,7 +4471,7 @@ public struct S #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4601,7 +4531,7 @@ Public Structure S End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4629,7 +4559,7 @@ readonly get #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Runtime.InteropServices; @@ -4696,7 +4626,7 @@ Public Event [|E|] As Action End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -4724,7 +4654,7 @@ public readonly event Action [|E|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -4792,7 +4722,7 @@ Public Event [|E|] As Action End Structure", (OriginatingProjectLanguage.CSharp, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {CodeAnalysisResources.InMemoryAssembly} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; @@ -4820,7 +4750,7 @@ public event Action [|E|] #endif", (OriginatingProjectLanguage.VisualBasic, false) => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // {FeaturesResources.location_unknown} -// Decompiled with ICSharpCode.Decompiler 6.1.0.5902 +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System; diff --git a/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs b/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs index 955e649141d88..2e91896436cbd 100644 --- a/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs +++ b/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs @@ -78,8 +78,9 @@ public async Task DynamicallyAddAnalyzer() Assert.Equal(10, worker.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory, WorkItem(747226, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/747226")] internal async Task SolutionAdded_Simple(BackgroundAnalysisScope analysisScope) @@ -105,8 +106,9 @@ internal async Task SolutionAdded_Simple(BackgroundAnalysisScope analysisScope) Assert.Equal(expectedDocumentEvents, worker.SyntaxDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory] internal async Task SolutionAdded_Complex(BackgroundAnalysisScope analysisScope) @@ -120,8 +122,9 @@ internal async Task SolutionAdded_Complex(BackgroundAnalysisScope analysisScope) Assert.Equal(expectedDocumentEvents, worker.SyntaxDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory] internal async Task Solution_Remove(BackgroundAnalysisScope analysisScope) @@ -135,8 +138,9 @@ internal async Task Solution_Remove(BackgroundAnalysisScope analysisScope) Assert.Equal(10, worker.InvalidateDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory] internal async Task Solution_Clear(BackgroundAnalysisScope analysisScope) @@ -150,8 +154,9 @@ internal async Task Solution_Clear(BackgroundAnalysisScope analysisScope) Assert.Equal(10, worker.InvalidateDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory] internal async Task Solution_Reload(BackgroundAnalysisScope analysisScope) @@ -169,8 +174,9 @@ internal async Task Solution_Reload(BackgroundAnalysisScope analysisScope) Assert.Equal(expectedProjectEvents, worker.ProjectIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory] internal async Task Solution_Change(BackgroundAnalysisScope analysisScope) @@ -192,8 +198,9 @@ internal async Task Solution_Change(BackgroundAnalysisScope analysisScope) Assert.Equal(expectedDocumentEvents, worker.SyntaxDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory] internal async Task Project_Add(BackgroundAnalysisScope analysisScope) @@ -218,8 +225,9 @@ internal async Task Project_Add(BackgroundAnalysisScope analysisScope) Assert.Equal(expectedDocumentEvents, worker.SyntaxDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory] internal async Task Project_Remove(BackgroundAnalysisScope analysisScope) @@ -236,8 +244,9 @@ internal async Task Project_Remove(BackgroundAnalysisScope analysisScope) Assert.Equal(5, worker.InvalidateDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory] internal async Task Project_Change(BackgroundAnalysisScope analysisScope) @@ -256,9 +265,10 @@ internal async Task Project_Change(BackgroundAnalysisScope analysisScope) Assert.Equal(1, worker.InvalidateDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Project_AssemblyName_Change(BackgroundAnalysisScope analysisScope, bool firstDocumentActive) @@ -283,9 +293,10 @@ internal async Task Project_AssemblyName_Change(BackgroundAnalysisScope analysis Assert.Equal(expectedDocumentEvents, worker.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Project_DefaultNamespace_Change(BackgroundAnalysisScope analysisScope, bool firstDocumentActive) @@ -310,9 +321,10 @@ internal async Task Project_DefaultNamespace_Change(BackgroundAnalysisScope anal Assert.Equal(expectedDocumentEvents, worker.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Project_AnalyzerOptions_Change(BackgroundAnalysisScope analysisScope, bool firstDocumentActive) @@ -339,9 +351,10 @@ internal async Task Project_AnalyzerOptions_Change(BackgroundAnalysisScope analy Assert.Equal(1, worker.NonSourceDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Project_OutputFilePath_Change(BackgroundAnalysisScope analysisScope, bool firstDocumentActive) @@ -366,9 +379,10 @@ internal async Task Project_OutputFilePath_Change(BackgroundAnalysisScope analys Assert.Equal(expectedDocumentEvents, worker.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Project_OutputRefFilePath_Change(BackgroundAnalysisScope analysisScope, bool firstDocumentActive) @@ -393,9 +407,10 @@ internal async Task Project_OutputRefFilePath_Change(BackgroundAnalysisScope ana Assert.Equal(expectedDocumentEvents, worker.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Project_CompilationOutputInfo_Change(BackgroundAnalysisScope analysisScope, bool firstDocumentActive) @@ -420,9 +435,10 @@ internal async Task Project_CompilationOutputInfo_Change(BackgroundAnalysisScope Assert.Equal(expectedDocumentEvents, worker.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Project_RunAnalyzers_Change(BackgroundAnalysisScope analysisScope, bool firstDocumentActive) @@ -468,7 +484,7 @@ public async Task Test_NeedsReanalysisOnOptionChanged() } [Fact] - public async Task Test_BackgroundAnalysisScopeOptionChanged_ActiveFile() + public async Task Test_BackgroundAnalysisScopeOptionChanged_OpenFiles() { using var workspace = new WorkCoordinatorWorkspace(SolutionCrawlerWorkspaceKind, incrementalAnalyzer: typeof(AnalyzerProviderNoWaitNoBlock)); var solutionInfo = GetInitialSolutionInfo_2Projects_10Documents(); @@ -476,9 +492,9 @@ public async Task Test_BackgroundAnalysisScopeOptionChanged_ActiveFile() MakeFirstDocumentActive(workspace.CurrentSolution.Projects.First()); await WaitWaiterAsync(workspace.ExportProvider); - Assert.Equal(BackgroundAnalysisScope.Default, SolutionCrawlerOptions.GetBackgroundAnalysisScope(workspace.Options, LanguageNames.CSharp)); + Assert.Equal(BackgroundAnalysisScope.ActiveFile, SolutionCrawlerOptions.GetBackgroundAnalysisScope(workspace.Options, LanguageNames.CSharp)); - var newAnalysisScope = BackgroundAnalysisScope.ActiveFile; + var newAnalysisScope = BackgroundAnalysisScope.OpenFiles; var worker = await ExecuteOperation(workspace, w => w.TryApplyChanges(w.CurrentSolution.WithOptions(w.CurrentSolution.Options.WithChangedOption(SolutionCrawlerOptions.BackgroundAnalysisScopeOption, LanguageNames.CSharp, newAnalysisScope)))); Assert.Equal(newAnalysisScope, SolutionCrawlerOptions.GetBackgroundAnalysisScope(workspace.Options, LanguageNames.CSharp)); @@ -495,7 +511,7 @@ public async Task Test_BackgroundAnalysisScopeOptionChanged_FullSolution() workspace.OnSolutionAdded(solutionInfo); await WaitWaiterAsync(workspace.ExportProvider); - Assert.Equal(BackgroundAnalysisScope.Default, SolutionCrawlerOptions.GetBackgroundAnalysisScope(workspace.Options, LanguageNames.CSharp)); + Assert.Equal(BackgroundAnalysisScope.ActiveFile, SolutionCrawlerOptions.GetBackgroundAnalysisScope(workspace.Options, LanguageNames.CSharp)); var newAnalysisScope = BackgroundAnalysisScope.FullSolution; var worker = await ExecuteOperation(workspace, w => w.TryApplyChanges(w.CurrentSolution.WithOptions(w.CurrentSolution.Options.WithChangedOption(SolutionCrawlerOptions.BackgroundAnalysisScopeOption, LanguageNames.CSharp, newAnalysisScope)))); @@ -506,8 +522,9 @@ public async Task Test_BackgroundAnalysisScopeOptionChanged_FullSolution() Assert.Equal(2, worker.ProjectIds.Count); } + [InlineData(BackgroundAnalysisScope.None)] [InlineData(BackgroundAnalysisScope.ActiveFile)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects)] + [InlineData(BackgroundAnalysisScope.OpenFiles)] [InlineData(BackgroundAnalysisScope.FullSolution)] [Theory] internal async Task Project_Reload(BackgroundAnalysisScope analysisScope) @@ -526,9 +543,10 @@ internal async Task Project_Reload(BackgroundAnalysisScope analysisScope) Assert.Equal(expectedProjectEvents, worker.ProjectIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Document_Add(BackgroundAnalysisScope analysisScope, bool activeDocument) @@ -559,9 +577,10 @@ internal async Task Document_Add(BackgroundAnalysisScope analysisScope, bool act Assert.Equal(expectedDocumentSemanticEvents, worker.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Document_Remove(BackgroundAnalysisScope analysisScope, bool removeActiveDocument) @@ -588,9 +607,10 @@ internal async Task Document_Remove(BackgroundAnalysisScope analysisScope, bool Assert.Equal(expectedDocumentInvalidatedEvents, worker.InvalidateDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Document_Reload(BackgroundAnalysisScope analysisScope, bool reloadActiveDocument) @@ -613,9 +633,10 @@ internal async Task Document_Reload(BackgroundAnalysisScope analysisScope, bool Assert.Equal(0, worker.InvalidateDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Document_Reanalyze(BackgroundAnalysisScope analysisScope, bool reanalyzeActiveDocument) @@ -658,9 +679,10 @@ internal async Task Document_Reanalyze(BackgroundAnalysisScope analysisScope, bo Assert.Equal(expectedReanalyzeDocumentCount, worker.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory, WorkItem(670335, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/670335")] internal async Task Document_Change(BackgroundAnalysisScope analysisScope, bool changeActiveDocument) @@ -683,9 +705,10 @@ internal async Task Document_Change(BackgroundAnalysisScope analysisScope, bool Assert.Equal(expectedDocumentEvents, worker.SyntaxDocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Document_AdditionalFileChange(BackgroundAnalysisScope analysisScope, bool firstDocumentActive) @@ -725,9 +748,10 @@ internal async Task Document_AdditionalFileChange(BackgroundAnalysisScope analys Assert.Empty(worker.NonSourceDocumentIds); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory] internal async Task Document_AnalyzerConfigFileChange(BackgroundAnalysisScope analysisScope, bool firstDocumentActive) @@ -764,9 +788,10 @@ internal async Task Document_AnalyzerConfigFileChange(BackgroundAnalysisScope an Assert.Equal(expectedDocumentSemanticEvents, worker.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory, WorkItem(670335, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/670335")] internal async Task Document_Cancellation(BackgroundAnalysisScope analysisScope, bool activeDocument) @@ -818,9 +843,10 @@ internal async Task Document_Cancellation(BackgroundAnalysisScope analysisScope, Assert.Equal(expectedDocumentSemanticEvents, analyzer.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory, WorkItem(670335, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/670335")] internal async Task Document_Cancellation_MultipleTimes(BackgroundAnalysisScope analysisScope, bool activeDocument) @@ -925,9 +951,10 @@ public async Task Document_InvocationReasons() Assert.Equal(5, analyzer.DocumentIds.Count); } + [InlineData(BackgroundAnalysisScope.None, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, false)] [InlineData(BackgroundAnalysisScope.ActiveFile, true)] - [InlineData(BackgroundAnalysisScope.OpenFilesAndProjects, false)] + [InlineData(BackgroundAnalysisScope.OpenFiles, false)] [InlineData(BackgroundAnalysisScope.FullSolution, false)] [Theory, WorkItem(670335, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/670335")] internal async Task Document_ActiveDocumentChanged(BackgroundAnalysisScope analysisScope, bool hasActiveDocumentBefore) @@ -949,14 +976,14 @@ internal async Task Document_ActiveDocumentChanged(BackgroundAnalysisScope analy var expectedSyntaxDocumentEvents = (analysisScope, hasActiveDocumentBefore) switch { (BackgroundAnalysisScope.ActiveFile, _) => 1, - (BackgroundAnalysisScope.OpenFilesAndProjects or BackgroundAnalysisScope.FullSolution, _) => 0, + (BackgroundAnalysisScope.OpenFiles or BackgroundAnalysisScope.FullSolution or BackgroundAnalysisScope.None, _) => 0, _ => throw ExceptionUtilities.Unreachable, }; var expectedDocumentEvents = (analysisScope, hasActiveDocumentBefore) switch { - (BackgroundAnalysisScope.ActiveFile, _) => 5, - (BackgroundAnalysisScope.OpenFilesAndProjects or BackgroundAnalysisScope.FullSolution, _) => 0, + (BackgroundAnalysisScope.ActiveFile, _) => 1, + (BackgroundAnalysisScope.OpenFiles or BackgroundAnalysisScope.FullSolution or BackgroundAnalysisScope.None, _) => 0, _ => throw ExceptionUtilities.Unreachable, }; @@ -1627,7 +1654,7 @@ internal static class Metadata private class Analyzer : IIncrementalAnalyzer2 { - public static readonly Option TestOption = new Option("TestOptions", "TestOption", defaultValue: true); + public static readonly Option2 TestOption = new Option2("TestOptions", "TestOption", defaultValue: true); public readonly ManualResetEventSlim BlockEvent; public readonly ManualResetEventSlim RunningEvent; @@ -1696,6 +1723,24 @@ public Task AnalyzeNonSourceDocumentAsync(TextDocument textDocument, InvocationR return Task.CompletedTask; } + public async Task ActiveDocumentSwitchedAsync(TextDocument document, CancellationToken cancellationToken) + { + if (SolutionCrawlerOptions.GetBackgroundAnalysisScope(document.Project) != BackgroundAnalysisScope.ActiveFile) + { + return; + } + + if (document is Document sourceDocument) + { + await AnalyzeSyntaxAsync(sourceDocument, InvocationReasons.ActiveDocumentSwitched, cancellationToken).ConfigureAwait(false); + await AnalyzeDocumentAsync(sourceDocument, bodyOpt: null, InvocationReasons.ActiveDocumentSwitched, cancellationToken).ConfigureAwait(false); + } + else + { + await AnalyzeNonSourceDocumentAsync(document, InvocationReasons.ActiveDocumentSwitched, cancellationToken).ConfigureAwait(false); + } + } + public Task RemoveDocumentAsync(DocumentId documentId, CancellationToken cancellationToken) { InvalidateDocumentIds.Add(documentId); @@ -1774,6 +1819,7 @@ public Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, Invocati public Task DocumentOpenAsync(Document document, CancellationToken cancellationToken) => Task.CompletedTask; public Task DocumentCloseAsync(Document document, CancellationToken cancellationToken) => Task.CompletedTask; public Task DocumentResetAsync(Document document, CancellationToken cancellationToken) => Task.CompletedTask; + public Task ActiveDocumentSwitchedAsync(TextDocument document, CancellationToken cancellationToken) => Task.CompletedTask; public Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken) => Task.CompletedTask; public Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken) => Task.CompletedTask; public Task RemoveDocumentAsync(DocumentId documentId, CancellationToken cancellationToken) => Task.CompletedTask; diff --git a/src/EditorFeatures/Test/StackTraceExplorer/StackTraceExplorerTests.cs b/src/EditorFeatures/Test/StackTraceExplorer/StackTraceExplorerTests.cs index ec43226c9a684..5988d9b7defe0 100644 --- a/src/EditorFeatures/Test/StackTraceExplorer/StackTraceExplorerTests.cs +++ b/src/EditorFeatures/Test/StackTraceExplorer/StackTraceExplorerTests.cs @@ -6,9 +6,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.StackTraceExplorer; using Microsoft.CodeAnalysis.Test.Utilities; @@ -508,7 +508,7 @@ async Task DoThingAsync() }"); } - [Fact(Skip = "Generated types/methods are not supported")] + [Fact] public Task TestSymbolFound_ExceptionLine_PropertySet() { return TestSymbolFoundAsync( @@ -528,11 +528,11 @@ public int I }"); } - [Fact(Skip = "Generated types/methods are not supported")] + [Fact] public Task TestSymbolFound_ExceptionLine_PropertyGet() { return TestSymbolFoundAsync( - @"at ConsoleApp4.MyClass.get_I(Int32 value)", + @"at ConsoleApp4.MyClass.get_I()", @"using System; namespace ConsoleApp4 @@ -548,7 +548,7 @@ public int I }"); } - [Fact(Skip = "Generated types/methods are not supported")] + [Fact] public Task TestSymbolFound_ExceptionLine_IndexerSet() { return TestSymbolFoundAsync( @@ -568,7 +568,7 @@ public int this[int i] }"); } - [Fact(Skip = "Generated types/methods are not supported")] + [Fact] public Task TestSymbolFound_ExceptionLine_IndexerGet() { return TestSymbolFoundAsync( @@ -588,7 +588,7 @@ public int this[int i] }"); } - [Fact(Skip = "Generated types/methods are not supported")] + [Fact] public Task TestSymbolFound_ExceptionLine_LocalFunction() { return TestSymbolFoundAsync( @@ -603,6 +603,44 @@ public void M() { LocalFunction(); + void [|LocalFunction|]() + { + throw new Exception(); + } + } + + public void LocalFunction() + { + } + } +}"); + } + + [Fact] + public Task TestSymbolFound_ExceptionLine_MultipleLocalFunctions() + { + return TestSymbolFoundAsync( + @"at ConsoleApp4.MyClass.g__LocalFunction|0_0()", + @"using System; + +namespace ConsoleApp4 +{ + class MyClass + { + public void M() + { + LocalFunction(); + + void [|LocalFunction|]() + { + throw new Exception(); + } + } + + public void M2() + { + LocalFunction(); + void LocalFunction() { throw new Exception(); @@ -612,14 +650,113 @@ void LocalFunction() }"); } - [Fact(Skip = "Generated types/methods are not supported")] + [Fact] + public Task TestSymbolFound_ExceptionLine_MultipleLocalFunctions2() + { + return TestSymbolFoundAsync( + @"at ConsoleApp4.MyClass.g__LocalFunction|0_0()", + @"using System; + +namespace ConsoleApp4 +{ + class MyClass + { + public void M() + { + LocalFunction(); + + void LocalFunction() + { + throw new Exception(); + } + } + + public void M2() + { + LocalFunction(); + + void [|LocalFunction()|] + { + throw new Exception(); + } + } + } +}"); + } + + [Fact] + public Task TestSymbolFound_ExceptionLine_MemberFunctionSameNameAsFunction() + { + return TestSymbolFoundAsync( + @"at ConsoleApp4.MyClass.LocalFunction()", + @"using System; + +namespace ConsoleApp4 +{ + class MyClass + { + public void M() + { + LocalFunction(); + + void LocalFunction() + { + throw new Exception(); + } + } + + public void [|LocalFunction|]() + { + } + } +}"); + } + + /// + /// Behavior for this test needs some explanation. Note that if there are multiple + /// local functions within a container, they will be uniquely identified by the + /// suffix. In this case we have g__Local|0_0 and g__Local|0_1 as the two local functions. + /// Resolution doesn't try to reverse engineer how these suffixes get produced, which means + /// that the first applicable symbol with the name "Local" inside the method "M" will be found. + /// Since local function resolution is done by searching the descendents of the method "M", the top + /// most local function matching the name will be the first the resolver sees and considers applicable. + /// This should get the user close to what they want, and hopefully is rare enough that it won't + /// be frequently encountered. + /// + [Fact] + public Task TestSymbolFound_ExceptionLine_NestedLocalFunctions() + { + return TestSymbolFoundAsync( + @"at C.g__Local|0_1()", + @"using System; + +class C +{ + public void M() + { + Local(); + + void [|Local|]() + { + Local(); + + void Local() + { + throw new Exception(); + } + } + } +}"); + } + + [Fact(Skip = "Top level local functions are not supported")] public Task TestSymbolFound_ExceptionLine_LocalInTopLevelStatement() { return TestSymbolFoundAsync( - @"at ConsoleApp4.MyClass.g__LocalFunction|0_0()", + @"at ConsoleApp4.Program.g__LocalInTopLevelStatement|0_0()", @"using System; -LoaclInTopLevelStatement(); +LocalInTopLevelStatement(); void [|LocalInTopLevelStatement|]() { diff --git a/src/EditorFeatures/Test/ValueTracking/CSharpValueTrackingTests.cs b/src/EditorFeatures/Test/ValueTracking/CSharpValueTrackingTests.cs index 6fc8f14078a0d..8ad25a41f096b 100644 --- a/src/EditorFeatures/Test/ValueTracking/CSharpValueTrackingTests.cs +++ b/src/EditorFeatures/Test/ValueTracking/CSharpValueTrackingTests.cs @@ -25,7 +25,7 @@ public async Task TestProperty(TestHost testHost) @" class C { - public string $$S { get; set; } = """"""; + public string $$S { get; set; } = """"; public void SetS(string s) { @@ -47,7 +47,7 @@ await ValidateItemsAsync( itemInfo: new[] { (7, "s"), - (3, "public string S { get; set; } = \"\""), + (3, "public string S { get; set; } = \"\";"), }); } @@ -59,7 +59,7 @@ public async Task TestPropertyWithThis(TestHost testHost) @" class C { - public string $$S { get; set; } = """"""; + public string $$S { get; set; } = """"; public void SetS(string s) { @@ -81,7 +81,7 @@ await ValidateItemsAsync( itemInfo: new[] { (7, "s"), - (3, "public string S { get; set; } = \"\""), + (3, "public string S { get; set; } = \"\";"), }); } @@ -93,7 +93,7 @@ public async Task TestField(TestHost testHost) @" class C { - private string $$_s = """"""; + private string $$_s = """"; public void SetS(string s) { @@ -127,7 +127,7 @@ public async Task TestFieldWithThis(TestHost testHost) @" class C { - private string $$_s = """"""; + private string $$_s = """"; public void SetS(string s) { @@ -276,7 +276,7 @@ public async Task MethodTracking1(TestHost testHost) @" class C { - public string S { get; set; } = """"""; + public string S { get; set; } = """"; public void SetS(string s) { @@ -387,7 +387,7 @@ public async Task MethodTracking2(TestHost testHost) @" class C { - public string S { get; set; } = """"""; + public string S { get; set; } = """"; public void SetS(string s) { diff --git a/src/EditorFeatures/Test/Workspaces/WorkspaceTests.cs b/src/EditorFeatures/Test/Workspaces/DefaultMefHostTests.cs similarity index 56% rename from src/EditorFeatures/Test/Workspaces/WorkspaceTests.cs rename to src/EditorFeatures/Test/Workspaces/DefaultMefHostTests.cs index 321882ab183bf..c892f286d3643 100644 --- a/src/EditorFeatures/Test/Workspaces/WorkspaceTests.cs +++ b/src/EditorFeatures/Test/Workspaces/DefaultMefHostTests.cs @@ -2,19 +2,25 @@ // The .NET 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.Mef; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces { + // We put [UseExportProvider] here even though the test ironically doesn't actually use the ExportProvider that's provided; + // setting this however still ensures the AfterTest portion runs which will clear out the existing catalog, and ensure that + // no other test accidentally uses the default catalog later if that other test is missing [UseExportProvider]. [UseExportProvider] - public class WorkspaceTests + public class DefaultMefHostTests { [Fact] public void TestDefaultCompositionIncludesFeaturesLayer() { + // For this specific test, we want to test that our default container works, so we'll remove any hooks + // that were created by other tests. + MefHostServices.TestAccessor.HookServiceCreation(null); + var ws = new AdhocWorkspace(); var csservice = ws.Services.GetLanguageServices(LanguageNames.CSharp).GetService(); diff --git a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb index a33e70d72b162..cc37902c4d5e1 100644 --- a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb +++ b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb @@ -52,6 +52,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference})) Dim project = workspace.CurrentSolution.Projects(0) + Dim options = CodeActionOptions.Default Assert.IsType(Of MockDiagnosticUpdateSourceRegistrationService)(workspace.GetService(Of IDiagnosticUpdateSourceRegistrationService)()) Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) @@ -73,9 +74,12 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Assert.Equal(1, diagnostics.Count()) ' Verify available codefix with a global fixer - Dim fixes = Await codefixService.GetFixesAsync(document, + Dim fixes = Await codefixService.GetFixesAsync( + document, (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + options, + CancellationToken.None) + Assert.Equal(0, fixes.Count()) ' Verify available codefix with a global fixer + a project fixer @@ -86,17 +90,22 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim projectAnalyzerReferences = ImmutableArray.Create(Of AnalyzerReference)(projectAnalyzerReference) project = project.WithAnalyzerReferences(projectAnalyzerReferences) document = project.Documents.Single() - fixes = Await codefixService.GetFixesAsync(document, - (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + fixes = Await codefixService.GetFixesAsync( + document, + (Await document.GetSyntaxRootAsync()).FullSpan, + options, + CancellationToken.None) Assert.Equal(1, fixes.Count()) ' Remove a project analyzer project = project.RemoveAnalyzerReference(projectAnalyzerReference) document = project.Documents.Single() - fixes = Await codefixService.GetFixesAsync(document, - (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + fixes = Await codefixService.GetFixesAsync( + document, + (Await document.GetSyntaxRootAsync()).FullSpan, + options, + CancellationToken.None) + Assert.Equal(0, fixes.Count()) End Using End Function @@ -120,6 +129,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference})) Dim project = workspace.CurrentSolution.Projects(0) + Dim options = CodeActionOptions.Default Assert.IsType(Of MockDiagnosticUpdateSourceRegistrationService)(workspace.GetService(Of IDiagnosticUpdateSourceRegistrationService)()) Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) @@ -141,9 +151,12 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Assert.Equal(1, diagnostics.Count()) ' Verify no codefix with a global fixer - Dim fixes = Await codefixService.GetFixesAsync(document, - (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + Dim fixes = Await codefixService.GetFixesAsync( + document, + (Await document.GetSyntaxRootAsync()).FullSpan, + options, + CancellationToken.None) + Assert.Equal(0, fixes.Count()) ' Verify no codefix with a global fixer + a project fixer @@ -154,9 +167,12 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim projectAnalyzerReferences = ImmutableArray.Create(Of AnalyzerReference)(projectAnalyzerReference) project = project.WithAnalyzerReferences(projectAnalyzerReferences) document = project.Documents.Single() - fixes = Await codefixService.GetFixesAsync(document, - (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + fixes = Await codefixService.GetFixesAsync( + document, + (Await document.GetSyntaxRootAsync()).FullSpan, + options, + CancellationToken.None) + Assert.Equal(0, fixes.Count()) End Using End Function diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb index 38561611d1d28..48272225e5cfc 100644 --- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.Shared.Options +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.SolutionCrawler Imports Microsoft.CodeAnalysis.UnitTests Imports Microsoft.CodeAnalysis.VisualBasic @@ -256,6 +256,11 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests Private Shared Sub VerifyAllAvailableDiagnostics(test As XElement, diagnostics As XElement, Optional ordered As Boolean = True) Using workspace = TestWorkspace.CreateWorkspace(test, composition:=s_composition) + ' Ensure that diagnostic service computes diagnostics for all open files, not just the active file (default mode) + For Each language In workspace.Projects.Select(Function(p) p.Language).Distinct() + Dim key = New OptionKey2(SolutionCrawlerOptions.BackgroundAnalysisScopeOption, language) + workspace.SetOptions(workspace.Options.WithChangedOption(key, BackgroundAnalysisScope.OpenFiles)) + Next Dim registrationService = workspace.Services.GetService(Of ISolutionCrawlerRegistrationService)() registrationService.Register(workspace) @@ -352,7 +357,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests id:=id, category:="test", message:=message, - enuMessageForBingSearch:=message, severity:=severity, defaultSeverity:=severity, isEnabledByDefault:=True, diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb index 5a47f2cc52cb4..e565227170f1e 100644 --- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb @@ -2330,6 +2330,23 @@ class MyClass End Using End Function + + Public Sub ReanalysisScopeExcludesMissingDocuments() + Dim test = + + + + + Using workspace = TestWorkspace.CreateWorkspace(test, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService) + Dim solution = workspace.CurrentSolution + Dim project = solution.Projects.Single() + + Dim missingDocumentId = DocumentId.CreateNewId(project.Id, "Missing ID") + Dim reanalysisScope = New SolutionCrawlerRegistrationService.ReanalyzeScope(documentIds:={missingDocumentId}) + Assert.Empty(reanalysisScope.GetDocumentIds(solution)) + End Using + End Sub + Private NotInheritable Class AnalyzerWithCustomDiagnosticCategory Inherits DiagnosticAnalyzer diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesCommandHandlerTests.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesCommandHandlerTests.vb index ee6ec6b0db7f8..9e1b933f67fa8 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesCommandHandlerTests.vb @@ -41,6 +41,7 @@ class C Dim context = New FindReferencesTests.TestContext() Dim commandHandler = New FindReferencesCommandHandler( New MockStreamingFindReferencesPresenter(context), + workspace.GlobalOptions, listenerProvider) Dim document = workspace.CurrentSolution.GetDocument(testDocument.Id) diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ParameterSymbol.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ParameterSymbol.vb index 09db7620f9455..3d0823dfdff91 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ParameterSymbol.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.ParameterSymbol.vb @@ -727,5 +727,173 @@ end class Await TestAPIAndFeature(input, kind, host) End Function + + + Public Async Function TestRecordParameter1(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int {|Definition:$$y|}) +{ + +} + +class P +{ + static void Main() + { + var f = new Goo(0, [|y|]: 1); + Console.WriteLine(f.[|y|]); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordParameter2(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int {|Definition:y|}) +{ + +} + +class P +{ + static void Main() + { + var f = new Goo(0, [|$$y|]: 1); + Console.WriteLine(f.[|y|]); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordParameterWithExplicitProperty1(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int {|Definition:$$y|}) +{ + public int y { get; } = [|y|]; +} + +class P +{ + static void Main() + { + var f = new Goo(0, [|y|]: 1); + Console.WriteLine(f.y); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordParameterWithExplicitProperty2(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int {|Definition:y|}) +{ + public int y { get; } = [|$$y|]; +} + +class P +{ + static void Main() + { + var f = new Goo(0, [|y|]: 1); + Console.WriteLine(f.y); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordParameterWithExplicitProperty3(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int {|Definition:y|}) +{ + public int y { get; } = [|y|]; +} + +class P +{ + static void Main() + { + var f = new Goo(0, [|$$y|]: 1); + Console.WriteLine(f.y); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordParameterWithNotPrimaryConstructor(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int y) +{ + public Goo(int {|Definition:$$y|}) { } +} + +class P +{ + static void Main() + { + var f = new Goo([|y|]: 1); + Console.WriteLine(f.y); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.PropertySymbols.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.PropertySymbols.vb index 9faa9028e087d..8294de72ce16d 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.PropertySymbols.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.PropertySymbols.vb @@ -1214,5 +1214,207 @@ class C2_2 : I2 Await TestAPI(input, host) End Function + + + Public Async Function TestRecordProperty1(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int {|Definition:$$y|}) +{ + +} + +class P +{ + static void Main() + { + var f = new Goo(0, [|y|]: 1); + Console.WriteLine(f.[|y|]); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordProperty2(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int {|Definition:y|}) +{ + +} + +class P +{ + static void Main() + { + var f = new Goo(0, [|$$y|]: 1); + Console.WriteLine(f.[|y|]); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordProperty3(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int {|Definition:y|}) +{ + +} + +class P +{ + static void Main() + { + var f = new Goo(0, [|y|]: 1); + Console.WriteLine(f.[|$$y|]); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordPropertyWithExplicitProperty1(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int y) +{ + public int {|Definition:$$y|} { get; } = y; +} + +class P +{ + static void Main() + { + var f = new Goo(0, y: 1); + Console.WriteLine(f.[|y|]); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordPropertyWithExplicitProperty2(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int y) +{ + public int {|Definition:y|} { get; } = y; +} + +class P +{ + static void Main() + { + var f = new Goo(0, y: 1); + Console.WriteLine(f.[|$$y|]); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordPropertyWithNotPrimaryConstructor1(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int y) +{ + public Goo(int {|Definition:$$y|}) + { + this.y = [|y|]; + } +} + +class P +{ + static void Main() + { + var f = new Goo([|y|]: 1); + Console.WriteLine(f.y); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function + + + Public Async Function TestRecordPropertyWithNotPrimaryConstructor2(kind As TestKind, host As TestHost) As Task + Dim input = + + + +using System; + +record Goo(int x, int {|Definition:$$y|}) +{ + public Goo(int y) + { + this.[|y|] = y; + } +} + +class P +{ + static void Main() + { + var f = new Goo(y: 1); + Console.WriteLine(f.[|y|]); + } +} + + + + + Await TestAPIAndFeature(input, kind, host) + End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb index e88e0ee842ffd..5a6fa64e6c50e 100644 --- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb +++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb @@ -5,10 +5,10 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Editor.FindUsages Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.FindSymbols Imports Microsoft.CodeAnalysis.FindUsages +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Remote.Testing Imports Microsoft.CodeAnalysis.Text @@ -40,7 +40,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences Private Async Function TestAPIAndFeature(definition As XElement, kind As TestKind, host As TestHost, Optional searchSingleFileOnly As Boolean = False, Optional uiVisibleOnly As Boolean = False) As Task If kind = TestKind.API Then - Await TestAPI(definition, host, searchSingleFileOnly, uiVisibleOnly, options:=Nothing) + Await TestAPI(definition, host, searchSingleFileOnly, uiVisibleOnly) Else Assert.Equal(TestKind.StreamingFeature, kind) Await TestStreamingFeature(definition, host, searchSingleFileOnly, uiVisibleOnly) @@ -73,7 +73,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences Dim findRefsService = startDocument.GetLanguageService(Of IFindUsagesService) Dim context = New TestContext() - Await findRefsService.FindReferencesAsync(startDocument, cursorPosition, context, CancellationToken.None) + Await findRefsService.FindReferencesAsync(context, startDocument, cursorPosition, CancellationToken.None) Dim expectedDefinitions = workspace.Documents.Where(Function(d) d.AnnotatedSpans.ContainsKey(DefinitionKey) AndAlso d.AnnotatedSpans(DefinitionKey).Any()). @@ -224,6 +224,13 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences Public ReadOnly Definitions As List(Of DefinitionItem) = New List(Of DefinitionItem)() Public ReadOnly References As List(Of SourceReferenceItem) = New List(Of SourceReferenceItem)() + Public Sub New() + End Sub + + Public Overrides Function GetOptionsAsync(language As String, cancellationToken As CancellationToken) As ValueTask(Of FindUsagesOptions) + Return ValueTaskFactory.FromResult(FindUsagesOptions.Default) + End Function + Public Function ShouldShow(definition As DefinitionItem) As Boolean If References.Any(Function(r) r.Definition Is definition) Then Return True @@ -253,22 +260,19 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences definition As XElement, host As TestHost, Optional searchSingleFileOnly As Boolean = False, - Optional uiVisibleOnly As Boolean = False, - Optional options As FindReferencesSearchOptions = Nothing) As Task + Optional uiVisibleOnly As Boolean = False) As Task - Await TestAPI(definition, host, explicit:=False, searchSingleFileOnly, uiVisibleOnly, options) - Await TestAPI(definition, host, explicit:=True, searchSingleFileOnly, uiVisibleOnly, options) + Await TestAPI(definition, host, searchSingleFileOnly, uiVisibleOnly, New FindReferencesSearchOptions(Explicit:=False)) + Await TestAPI(definition, host, searchSingleFileOnly, uiVisibleOnly, New FindReferencesSearchOptions(Explicit:=True)) End Function Private Async Function TestAPI( definition As XElement, host As TestHost, - explicit As Boolean, searchSingleFileOnly As Boolean, uiVisibleOnly As Boolean, options As FindReferencesSearchOptions) As Task - options = If(options, FindReferencesSearchOptions.Default) - options = options.With(explicit:=explicit) + Using workspace = TestWorkspace.Create(definition, composition:=s_composition.WithTestHostParts(host)) workspace.SetTestLogger(AddressOf _outputHelper.WriteLine) diff --git a/src/EditorFeatures/Test2/GoToBase/GoToBaseTestsBase.vb b/src/EditorFeatures/Test2/GoToBase/GoToBaseTestsBase.vb index 22d596ea3da32..603229db9867c 100644 --- a/src/EditorFeatures/Test2/GoToBase/GoToBaseTestsBase.vb +++ b/src/EditorFeatures/Test2/GoToBase/GoToBaseTestsBase.vb @@ -3,8 +3,8 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.FindUsages -Imports Microsoft.CodeAnalysis.Editor.GoToBase +Imports Microsoft.CodeAnalysis.FindUsages +Imports Microsoft.CodeAnalysis.GoToBase Imports Microsoft.CodeAnalysis.Remote.Testing Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToBase @@ -16,7 +16,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToBase testHost:=TestHost.InProcess, Async Function(document As Document, position As Integer, context As SimpleFindUsagesContext) Dim gotoBaseService = document.GetLanguageService(Of IGoToBaseService) - Await gotoBaseService.FindBasesAsync(document, position, context, CancellationToken.None) + Await gotoBaseService.FindBasesAsync(context, document, position, CancellationToken.None) End Function, shouldSucceed, metadataDefinitions) End Function diff --git a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb index 0a465509c5710..cfc8a9bd7d3a0 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionCommandHandlerTests.vb @@ -96,7 +96,7 @@ class C Dim navigatedTo = False Dim threadingContext = workspace.ExportProvider.GetExportedValue(Of IThreadingContext)() - Dim presenter = New MockStreamingFindUsagesPresenter(Sub() navigatedTo = True) + Dim presenter = New MockStreamingFindUsagesPresenter(workspace.GlobalOptions, Sub() navigatedTo = True) Dim cursorBuffer = cursorDocument.GetTextBuffer() Dim document = workspace.CurrentSolution.GetDocument(cursorDocument.Id) diff --git a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionTestsBase.vb b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionTestsBase.vb index d97d0b6a347f5..b2478a1aa7f65 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionTestsBase.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/GoToDefinitionTestsBase.vb @@ -40,7 +40,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToDefinition Dim presenterCalled As Boolean = False Dim threadingContext = workspace.ExportProvider.GetExportedValue(Of IThreadingContext)() - Dim presenter = New MockStreamingFindUsagesPresenter(Sub() presenterCalled = True) + Dim presenter = New MockStreamingFindUsagesPresenter(workspace.GlobalOptions, Sub() presenterCalled = True) Dim actualResult = executeOnDocument(document, cursorPosition, threadingContext, presenter) Assert.Equal(expectedResult, actualResult) diff --git a/src/EditorFeatures/Test2/GoToHelpers/GoToHelpers.vb b/src/EditorFeatures/Test2/GoToHelpers/GoToHelpers.vb index 0d354ff4bd3aa..71e4b548d3ad2 100644 --- a/src/EditorFeatures/Test2/GoToHelpers/GoToHelpers.vb +++ b/src/EditorFeatures/Test2/GoToHelpers/GoToHelpers.vb @@ -4,7 +4,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Editor.FindUsages +Imports Microsoft.CodeAnalysis.FindUsages Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces @@ -25,7 +25,7 @@ Friend Class GoToHelpers Dim solution = workspace.CurrentSolution Dim document = solution.GetDocument(documentWithCursor.Id) - Dim context = New SimpleFindUsagesContext() + Dim context = New SimpleFindUsagesContext(workspace.GlobalOptions) Await testingMethod(document, position, context) If Not shouldSucceed Then @@ -69,7 +69,7 @@ Friend Class GoToHelpers metadataDefinitions = {} End If - Assert.Equal(actualDefintionsWithoutSpans, metadataDefinitions) + AssertEx.Equal(metadataDefinitions, actualDefintionsWithoutSpans) End If End Using End Function diff --git a/src/EditorFeatures/Test2/GoToImplementation/GoToImplementationTests.vb b/src/EditorFeatures/Test2/GoToImplementation/GoToImplementationTests.vb index 194417e33c655..8b48e6fc1831e 100644 --- a/src/EditorFeatures/Test2/GoToImplementation/GoToImplementationTests.vb +++ b/src/EditorFeatures/Test2/GoToImplementation/GoToImplementationTests.vb @@ -3,22 +3,23 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.Remote.Testing -Imports Microsoft.CodeAnalysis.Editor.FindUsages +Imports Microsoft.CodeAnalysis.FindUsages Imports System.Threading Namespace Microsoft.CodeAnalysis.Editor.UnitTests.GoToImplementation <[UseExportProvider]> Public Class GoToImplementationTests - Private Shared Async Function TestAsync(workspaceDefinition As XElement, host As TestHost, Optional shouldSucceed As Boolean = True) As Task + Private Shared Async Function TestAsync(workspaceDefinition As XElement, host As TestHost, Optional shouldSucceed As Boolean = True, Optional metadataDefinitions As String() = Nothing) As Task Await GoToHelpers.TestAsync( workspaceDefinition, host, Async Function(document As Document, position As Integer, context As SimpleFindUsagesContext) As Task Dim findUsagesService = document.GetLanguageService(Of IFindUsagesService) - Await findUsagesService.FindImplementationsAsync(document, position, context, CancellationToken.None).ConfigureAwait(False) + Await findUsagesService.FindImplementationsAsync(context, document, position, CancellationToken.None).ConfigureAwait(False) End Function, - shouldSucceed) + shouldSucceed, + metadataDefinitions) End Function @@ -404,7 +405,7 @@ class C : IDisposable - Await TestAsync(workspace, host) + Await TestAsync(workspace, host, metadataDefinitions:={"mscorlib:ActivationContext.Dispose", "mscorlib:AsymmetricAlgorithm.Dispose", "mscorlib:AsyncFlowControl.Dispose", "mscorlib:BinaryReader.Dispose", "mscorlib:BinaryWriter.Dispose", "mscorlib:CancellationTokenRegistration.Dispose", "mscorlib:CancellationTokenSource.Dispose", "mscorlib:CharEnumerator.Dispose", "mscorlib:CountdownEvent.Dispose", "mscorlib:CriticalHandle.Dispose", "mscorlib:CryptoAPITransform.Dispose", "mscorlib:DeriveBytes.Dispose", "mscorlib:Enumerator.Dispose", "mscorlib:Enumerator.Dispose", "mscorlib:Enumerator.Dispose", "mscorlib:Enumerator.Dispose", "mscorlib:EventListener.Dispose", "mscorlib:EventSource.Dispose", "mscorlib:ExecutionContext.Dispose", "mscorlib:FromBase64Transform.Dispose", "mscorlib:HashAlgorithm.Dispose", "mscorlib:HostExecutionContext.Dispose", "mscorlib:IsolatedStorageFile.Dispose", "mscorlib:ManualResetEventSlim.Dispose", "mscorlib:MemoryFailPoint.Dispose", "mscorlib:RandomNumberGenerator.Dispose", "mscorlib:RegistryKey.Dispose", "mscorlib:ResourceReader.Dispose", "mscorlib:ResourceSet.Dispose", "mscorlib:ResourceWriter.Dispose", "mscorlib:RijndaelManagedTransform.Dispose", "mscorlib:SafeHandle.Dispose", "mscorlib:SecureString.Dispose", "mscorlib:SecurityContext.Dispose", "mscorlib:SemaphoreSlim.Dispose", "mscorlib:Stream.Dispose", "mscorlib:SymmetricAlgorithm.Dispose", "mscorlib:Task.Dispose", "mscorlib:TextReader.Dispose", "mscorlib:TextWriter.Dispose", "mscorlib:ThreadLocal.Dispose", "mscorlib:Timer.Dispose", "mscorlib:ToBase64Transform.Dispose", "mscorlib:UnmanagedMemoryAccessor.Dispose", "mscorlib:WaitHandle.Dispose", "mscorlib:WindowsIdentity.Dispose", "mscorlib:WindowsImpersonationContext.Dispose", "mscorlib:X509Certificate.Dispose", "System.Core:CngKey.Dispose", "System.Core:CounterSet.Dispose", "System.Core:CounterSetInstance.Dispose", "System.Core:CounterSetInstanceCounterDataSet.Dispose", "System.Core:ECDiffieHellmanPublicKey.Dispose", "System.Core:Enumerator.Dispose", "System.Core:EventLogConfiguration.Dispose", "System.Core:EventLogPropertySelector.Dispose", "System.Core:EventLogReader.Dispose", "System.Core:EventLogSession.Dispose", "System.Core:EventLogWatcher.Dispose", "System.Core:EventProvider.Dispose", "System.Core:EventRecord.Dispose", "System.Core:MemoryMappedFile.Dispose", "System.Core:ProviderMetadata.Dispose", "System.Core:ReaderWriterLockSlim.Dispose", "System:AlternateViewCollection.Dispose", "System:AttachmentBase.Dispose", "System:AttachmentCollection.Dispose", "System:Barrier.Dispose", "System:BlockingCollection.Dispose", "System:ClientWebSocket.Dispose", "System:Component.Dispose", "System:Container.Dispose", "System:Enumerator.Dispose", "System:Enumerator.Dispose", "System:Enumerator.Dispose", "System:Enumerator.Dispose", "System:Enumerator.Dispose", "System:Enumerator.Dispose", "System:Enumerator.Dispose", "System:EventHandlerList.Dispose", "System:License.Dispose", "System:LinkedResourceCollection.Dispose", "System:MailMessage.Dispose", "System:MarshalByValueComponent.Dispose", "System:ServiceContainer.Dispose", "System:SmtpClient.Dispose", "System:Socket.Dispose", "System:SocketAsyncEventArgs.Dispose", "System:TcpClient.Dispose", "System:TraceListener.Dispose", "System:UdpClient.Dispose", "System:WebResponse.Dispose", "System:X509Chain.Dispose", "System:X509Store.Dispose"}) End Function diff --git a/src/EditorFeatures/Test2/IntelliSense/AbstractIntellisenseQuickInfoBuilderTests.vb b/src/EditorFeatures/Test2/IntelliSense/AbstractIntellisenseQuickInfoBuilderTests.vb index 573049bddb9e7..b569aa20e4b83 100644 --- a/src/EditorFeatures/Test2/IntelliSense/AbstractIntellisenseQuickInfoBuilderTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/AbstractIntellisenseQuickInfoBuilderTests.vb @@ -9,6 +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.QuickInfo Imports Microsoft.CodeAnalysis.Shared.TestHooks Imports Microsoft.VisualStudio.Core.Imaging @@ -67,7 +68,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Dim languageServiceProvider = workspace.Services.GetLanguageServices(language) Dim quickInfoService = languageServiceProvider.GetRequiredService(Of QuickInfoService) - Dim codeAnalysisQuickInfoItem = Await quickInfoService.GetQuickInfoAsync(document, cursorPosition, CancellationToken.None).ConfigureAwait(False) + Dim codeAnalysisQuickInfoItem = Await quickInfoService.GetQuickInfoAsync(document, cursorPosition, SymbolDescriptionOptions.Default, CancellationToken.None).ConfigureAwait(False) Dim trackingSpan = New Mock(Of ITrackingSpan)(MockBehavior.Strict) With { .DefaultValue = DefaultValue.Mock diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb index 5af433edb4f94..d591d1bb73273 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -50,10 +50,10 @@ public class C2 showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) state.SendTypeChars(".") - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=False) state.SendTypeChars("IP") - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=True) state.SendTab() state.SendTypeChars(": 2 }") @@ -121,10 +121,10 @@ End Class , showCompletionInArgumentLists:=showCompletionInArgumentLists) state.SendTypeChars(".") - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=False) state.SendTypeChars("IP") - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=True) state.SendTab() state.SendTypeChars(": 2 }") @@ -158,10 +158,10 @@ public class C3 showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) state.SendTypeChars(".") - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=False) state.SendTypeChars("IP") - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=True) state.SendTab() state.SendTypeChars(": 2 }") @@ -195,16 +195,16 @@ public class C3 showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) state.SendTypeChars(".") - Await state.AssertSelectedCompletionItem(displayText:="C3Field:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="C3Field", isHardSelected:=False) state.SendTypeChars("CF") - Await state.AssertSelectedCompletionItem(displayText:="C3Field:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="C3Field", isHardSelected:=True) state.SendTypeChars(".") - Await state.AssertSelectedCompletionItem(displayText:="IntField:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="IntField", isHardSelected:=False) state.SendTypeChars("IF") - Await state.AssertSelectedCompletionItem(displayText:="IntField:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="IntField", isHardSelected:=True) state.SendTab() state.SendTypeChars(": 2 }") @@ -258,17 +258,17 @@ public class C2 showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) state.SendTypeChars("{ ") - Await state.AssertSelectedCompletionItem(displayText:="CProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="CProperty", isHardSelected:=False) state.SendTypeChars("CP") - Await state.AssertSelectedCompletionItem(displayText:="CProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="CProperty", isHardSelected:=True) state.SendTypeChars(".") Assert.Contains("c is { CProperty.", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=False) state.SendTypeChars("IP") - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=True) state.SendTab() state.SendTypeChars(": 2 }") @@ -328,18 +328,18 @@ public class C2 showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) state.SendTypeChars(", ") - Await state.AssertSelectedCompletionItem(displayText:="CProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="CProperty", isHardSelected:=False) state.SendTypeChars("CP") - Await state.AssertSelectedCompletionItem(displayText:="CProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="CProperty", isHardSelected:=True) state.SendTypeChars(".") Assert.Contains("is { CProperty.IntProperty: 2, CProperty.", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) ' Note: same completion is offered a second time - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=False) state.SendTypeChars("SP") - Await state.AssertSelectedCompletionItem(displayText:="ShortProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="ShortProperty", isHardSelected:=True) state.SendTab() state.SendTypeChars(": 3") @@ -378,10 +378,10 @@ public class C2 state.SendTypeChars(".") Assert.Contains("is { CProperty: { IntProperty: 2 }, CProperty.", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) ' Note: same completion is offered a second time - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=False) state.SendTypeChars("SP") - Await state.AssertSelectedCompletionItem(displayText:="ShortProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="ShortProperty", isHardSelected:=True) state.SendTab() state.SendTypeChars(": 3") @@ -412,10 +412,10 @@ public class C2 showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) state.SendTypeChars(" ") - Await state.AssertSelectedCompletionItem(displayText:="CProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="CProperty", isHardSelected:=False) state.SendTypeChars("CP") - Await state.AssertSelectedCompletionItem(displayText:="CProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="CProperty", isHardSelected:=True) state.SendTypeChars(".") Assert.Contains("is { CProperty. CProperty.IntProperty: 2 }", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) @@ -452,10 +452,10 @@ public class C2 showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) state.SendTypeChars(" ") - Await state.AssertSelectedCompletionItem(displayText:="ShortProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="ShortProperty", isHardSelected:=False) state.SendTypeChars("SP") - Await state.AssertSelectedCompletionItem(displayText:="ShortProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="ShortProperty", isHardSelected:=True) state.SendTab() state.SendTypeChars(": 3,") @@ -636,7 +636,7 @@ class C showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) state.SendTypeChars("w") - Await state.AssertSelectedCompletionItem(displayText:="with", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="with", isHardSelected:=True) state.SendTab() state.SendTypeChars(" { ") Await state.AssertSelectedCompletionItem(displayText:="Property", isHardSelected:=False) @@ -793,9 +793,8 @@ class C , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options.WithChangedOption( - CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendTypeChars("repl") state.SendTab() @@ -1057,9 +1056,7 @@ class Class1 }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.EnterKeyBehavior, LanguageNames.CSharp, EnterKeyRule.AfterFullyTypedWord))) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.CSharp), EnterKeyRule.AfterFullyTypedWord) state.SendTypeChars("System.TimeSpan.FromMin") state.SendReturn() @@ -1087,9 +1084,9 @@ class Class1 } }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.EnterKeyBehavior, LanguageNames.CSharp, EnterKeyRule.AfterFullyTypedWord))) + + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.CSharp), EnterKeyRule.AfterFullyTypedWord) state.SendTypeChars("System.TimeSpan.FromMinutes") state.SendReturn() @@ -1446,9 +1443,8 @@ class Variable }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertSelectedCompletionItem(displayText:="as", isSoftSelected:=True) @@ -1477,9 +1473,8 @@ class Variable }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertSelectedCompletionItem(displayText:="as", isSoftSelected:=True) @@ -1961,13 +1956,13 @@ class Class state.SendTypeChars("C") Await state.AssertSelectedCompletionItem(displayText:="Class", isHardSelected:=True) state.SendTypeChars(" { P") - Await state.AssertSelectedCompletionItem(displayText:="Prop", displayTextSuffix:=":", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="Prop", displayTextSuffix:="", isHardSelected:=True) state.SendTypeChars(":") Assert.Contains("{ Prop:", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) state.SendTypeChars(" 0, ") - Await state.AssertSelectedCompletionItem(displayText:="OtherProp", displayTextSuffix:=":", isSoftSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="OtherProp", displayTextSuffix:="", isSoftSelected:=True) state.SendTypeChars("O") - Await state.AssertSelectedCompletionItem(displayText:="OtherProp", displayTextSuffix:=":", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="OtherProp", displayTextSuffix:="", isHardSelected:=True) state.SendTypeChars(": 1 }") Assert.Contains("is Class { Prop: 0, OtherProp: 1 }", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) End Using @@ -1995,15 +1990,15 @@ class Class state.SendTypeChars(" ") Assert.Contains("is Class", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) state.SendTypeChars("{ P") - Await state.AssertSelectedCompletionItem(displayText:="Prop", displayTextSuffix:=":", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="Prop", displayTextSuffix:="", isHardSelected:=True) state.SendTypeChars(" ") Assert.Contains("is Class { Prop ", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) state.SendTypeChars(":") Assert.Contains("is Class { Prop :", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) state.SendTypeChars(" 0, ") - Await state.AssertSelectedCompletionItem(displayText:="OtherProp", displayTextSuffix:=":", isSoftSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="OtherProp", displayTextSuffix:="", isSoftSelected:=True) state.SendTypeChars("O") - Await state.AssertSelectedCompletionItem(displayText:="OtherProp", displayTextSuffix:=":", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="OtherProp", displayTextSuffix:="", isHardSelected:=True) state.SendTypeChars(" ") Assert.Contains("is Class { Prop : 0, OtherProp", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) state.SendTypeChars(": 1 }") @@ -4028,9 +4023,8 @@ class$$ C }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertCompletionSession() @@ -4060,9 +4054,8 @@ class Program }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertCompletionSession() @@ -4785,9 +4778,8 @@ class Program ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) For Each c In "Offset" state.SendBackspace() @@ -4816,9 +4808,8 @@ class Program ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) For Each c In "Offset." state.SendBackspace() @@ -4948,8 +4939,8 @@ class C Dim completionService = DirectCast(state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)(), CompletionServiceWithProviders) Dim provider = completionService.GetTestAccessor().GetAllProviders(ImmutableHashSet(Of String).Empty).OfType(Of BooleanTaskControlledCompletionProvider)().Single() - Dim globalOptions = state.Workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) state.SendTypeChars("Sys.") Await state.AssertNoCompletionSession() @@ -4969,8 +4960,8 @@ class C extraExportedTypes:={GetType(CompletedTaskControlledCompletionProvider)}.ToList(), showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim globalOptions = state.Workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) state.SendTypeChars("Sys") Await state.AssertSelectedCompletionItem(displayText:="System") @@ -5003,8 +4994,8 @@ class C Dim completionService = DirectCast(state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)(), CompletionServiceWithProviders) Dim provider = completionService.GetTestAccessor().GetAllProviders(ImmutableHashSet(Of String).Empty).OfType(Of BooleanTaskControlledCompletionProvider)().Single() - Dim globalOptions = state.Workspace.GetService(Of IGlobalOptionService) - globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), False) state.SendTypeChars("Sys") @@ -5450,11 +5441,8 @@ class Program , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim key = New OptionKey(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp) - - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(key, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertSelectedCompletionItem(displayText:="Environment", isHardSelected:=True) @@ -5763,9 +5751,8 @@ class C } ) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendTypeChars("""") @@ -6003,9 +5990,8 @@ public class Program , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendInvokeCompletionList() state.SendBackspace() @@ -6030,9 +6016,8 @@ public class Program , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendInvokeCompletionList() state.SelectAndMoveCaret(-6) @@ -6082,9 +6067,8 @@ class C }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertCompletionItemsContainAll("WriteLine") @@ -6330,9 +6314,8 @@ class C , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertCompletionSession() @@ -6359,9 +6342,8 @@ class C , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertCompletionSession() @@ -6448,9 +6430,8 @@ class C Dim completionService = DirectCast(state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)(), CompletionServiceWithProviders) Dim provider = completionService.GetTestAccessor().GetAllProviders(ImmutableHashSet(Of String).Empty).OfType(Of IntelliCodeMockProvider)().Single() - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertCompletionItemsContainAll("Normalize", "★ Normalize") @@ -6560,9 +6541,8 @@ class C Dim completionService = DirectCast(state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)(), CompletionServiceWithProviders) Dim provider = completionService.GetTestAccessor().GetAllProviders(ImmutableHashSet(Of String).Empty).OfType(Of IntelliCodeMockProvider)().Single() - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendTypeChars(".nor") Await state.AssertCompletionItemsContainAll("Normalize", "★ Normalize") @@ -6613,9 +6593,8 @@ class C Dim completionService = DirectCast(state.Workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)(), CompletionServiceWithProviders) Dim provider = completionService.GetTestAccessor().GetAllProviders(ImmutableHashSet(Of String).Empty).OfType(Of IntelliCodeMockProvider)().Single() - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendTypeChars(".nor") Await state.AssertCompletionItemsContainAll("Normalize", "★ Normalize") @@ -6691,9 +6670,7 @@ namespace NS2 Dim completionService = CType(document.GetLanguageService(Of CompletionService)(), CompletionServiceWithProviders) completionService.GetTestAccessor().SuppressPartialSemantics() - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.WaitForUIRenderedAsync() @@ -6750,10 +6727,7 @@ namespace NS2 Dim completionService = CType(document.GetLanguageService(Of CompletionService)(), CompletionServiceWithProviders) completionService.GetTestAccessor().SuppressPartialSemantics() - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.WaitForUIRenderedAsync() @@ -6790,10 +6764,7 @@ namespace NS2 ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, False))) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), False) ' trigger completion with import completion disabled state.SendInvokeCompletionList() @@ -6831,7 +6802,7 @@ namespace NS2 state.SendInvokeCompletionList() Await state.WaitForUIRenderedAsync() - ' should not show unimported item even with cache populated + ' should not show unimported item by default Await state.AssertCompletionItemsDoNotContainAny({"Bar"}) state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=False) @@ -6861,10 +6832,7 @@ namespace NS2 ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) ' trigger completion with import completion enabled state.SendInvokeCompletionList() @@ -6886,7 +6854,7 @@ namespace NS2 state.SendInvokeCompletionList() Await state.WaitForUIRenderedAsync() - ' now cache is populated + ' show expanded items by default Await state.AssertSelectedCompletionItem(displayText:="Bar", inlineDescription:="NS2") state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) @@ -6895,7 +6863,7 @@ namespace NS2 - Public Async Function NoExpanderAvailableWhenNotInTypeContext(showCompletionInArgumentLists As Boolean) As Task + Public Async Function ExpanderAvailableWhenNotInTypeContextButNotAddingAnyItems(showCompletionInArgumentLists As Boolean) As Task Using state = TestStateFactory.CreateCSharpTestState( , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) ' trigger completion with import completion enabled state.SendInvokeCompletionList() Await state.WaitForUIRenderedAsync() - state.AssertCompletionItemExpander(isAvailable:=False, isSelected:=False) + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=False) + Dim length = state.GetCompletionItems().Count + + state.SetCompletionItemExpanderState(isSelected:=True) + Await state.WaitForAsynchronousOperationsAsync() + Await state.WaitForUIRenderedAsync() + + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) + Assert.Equal(length, state.GetCompletionItems().Count) End Using End Function @@ -7341,19 +7315,12 @@ namespace NS2 } " - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, 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() - ' make sure expander is selected - state.SetCompletionItemExpanderState(isSelected:=True) - Await state.WaitForAsynchronousOperationsAsync() - Await state.WaitForUIRenderedAsync() - state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) Await state.AssertSelectedCompletionItem(displayText:="Bar", displayTextSuffix:="<>") @@ -7416,19 +7383,12 @@ namespace NS2 } " - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, 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() - ' make sure expander is selected - state.SetCompletionItemExpanderState(isSelected:=True) - Await state.WaitForAsynchronousOperationsAsync() - Await state.WaitForUIRenderedAsync() - state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) Await state.AssertSelectedCompletionItem(displayText:="Bar") @@ -7491,19 +7451,12 @@ namespace NS2 } " - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, 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() - ' make sure expander is selected - state.SetCompletionItemExpanderState(isSelected:=True) - Await state.WaitForAsynchronousOperationsAsync() - Await state.WaitForUIRenderedAsync() - state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) Await state.AssertSelectedCompletionItem(displayText:="ABar") @@ -7566,19 +7519,12 @@ namespace NS2 } " - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, 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() - ' make sure expander is selected - state.SetCompletionItemExpanderState(isSelected:=True) - Await state.WaitForAsynchronousOperationsAsync() - Await state.WaitForUIRenderedAsync() - state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) Await state.AssertSelectedCompletionItem(displayText:="Bar", inlineDescription:="") state.SendTab() @@ -7642,19 +7588,12 @@ namespace NS2 } " - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, 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() - ' make sure expander is selected - state.SetCompletionItemExpanderState(isSelected:=True) - Await state.WaitForAsynchronousOperationsAsync() - Await state.WaitForUIRenderedAsync() - Await state.AssertSelectedCompletionItem(displayText:="Bar", inlineDescription:="NS2") state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) @@ -7687,19 +7626,12 @@ namespace OtherNS , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, 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() - ' make sure expander is selected so all unimported items are in the list - state.SetCompletionItemExpanderState(isSelected:=True) - Await state.WaitForAsynchronousOperationsAsync() - Await state.WaitForUIRenderedAsync() - Await state.AssertSelectedCompletionItem(displayText:="designer") state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) End Using @@ -7736,9 +7668,8 @@ namespace NS } , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, False))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), False) state.SendTypeChars("task") Await state.WaitForAsynchronousOperationsAsync() @@ -7790,9 +7721,8 @@ namespace NS2 , showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, False))) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) ' trigger completion with import completion disabled state.SendInvokeCompletionList() @@ -7806,9 +7736,7 @@ namespace NS2 state.SendEscape() Await state.AssertNoCompletionSession() - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1) _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendTypeChars("mytask") Await state.WaitForAsynchronousOperationsAsync() @@ -7851,9 +7779,9 @@ namespace NS } ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.ShowNameSuggestions, LanguageNames.CSharp, True))) + + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.ShowNameSuggestions, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.AssertCompletionItemsContainAll("foo123Bar", "foo123", "foo", "bar") @@ -7882,9 +7810,9 @@ namespace NS } ]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.ShowNameSuggestions, LanguageNames.CSharp, True))) + + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.ShowNameSuggestions, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.AssertCompletionItemsContainAll("foo123", "foo") @@ -8317,8 +8245,9 @@ namespace B } } } ) - state.Workspace.SetOptions(state.Workspace.Options.WithChangedOption( - CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True)) + + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.SendInvokeCompletionList() state.AssertItemsInOrder(New String() { "A", ' Method, properties, and imported extension methods alphabetical ordered @@ -8636,9 +8565,7 @@ public class AA } }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.SetOptions(state.Workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True) _ - .WithChangedOption(CompletionOptions.Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, -1)) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) Dim expectedText = $" using CC; @@ -8684,7 +8611,7 @@ public class AA } }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.SetOptions(state.Workspace.Options.WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True)) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.WaitForAsynchronousOperationsAsync() @@ -8737,7 +8664,9 @@ public class AA } }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.SetOptions(state.Workspace.Options.WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True)) + + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.WaitForAsynchronousOperationsAsync() @@ -8784,7 +8713,9 @@ public class AA } }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.SetOptions(state.Workspace.Options.WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True)) + + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.WaitForAsynchronousOperationsAsync() @@ -8825,7 +8756,9 @@ public class AA private static T GetSomething<T>() => (T)Activator.GetInstance(typeof(T)); }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.SetOptions(state.Workspace.Options.WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True)) + + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.WaitForAsynchronousOperationsAsync() @@ -8873,7 +8806,9 @@ namespace Bar1 } }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.SetOptions(state.Workspace.Options.WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True)) + + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.WaitForAsynchronousOperationsAsync() @@ -8921,7 +8856,9 @@ public unsafe class AA public static void Bar() {} }, showCompletionInArgumentLists:=showCompletionInArgumentLists) - state.Workspace.SetOptions(state.Workspace.Options.WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True)) + + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.WaitForAsynchronousOperationsAsync() @@ -9285,9 +9222,8 @@ class C }]]>, showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options.WithChangedOption( - CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendBackspace() Await state.AssertSelectedCompletionItem("xml", isSoftSelected:=True).ConfigureAwait(True) @@ -9342,9 +9278,8 @@ class Repro extraExportedTypes:={GetType(PreselectionProvider)}.ToList(), showCompletionInArgumentLists:=showCompletionInArgumentLists) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, True))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.AssertCompletionItemsContainAll({"★ length", "length", "Length"}) @@ -9428,10 +9363,10 @@ public class C Await state.AssertSelectedCompletionItem(displayText:="async", isHardSelected:=False) state.SendTypeChars("{ ") - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=False) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=False) state.SendTypeChars("IP") - Await state.AssertSelectedCompletionItem(displayText:="IntProperty:", isHardSelected:=True) + Await state.AssertSelectedCompletionItem(displayText:="IntProperty", isHardSelected:=True) state.SendTab() state.SendTypeChars(": 1") @@ -9503,6 +9438,131 @@ public class C End Using End Function + + + Public Async Function CompletionInRawStringLiteralInterpolation_SingleLine(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class C +{ + void M(int y) + { + var s = $"""""{$$}"""""; + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("ne") + Await state.AssertSelectedCompletionItem(displayText:="new", isHardSelected:=True) + End Using + End Function + + + + Public Async Function CompletionInRawStringLiteralInterpolation_SingleLine_MultiBrace(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class C +{ + void M(int y) + { + var s = ${|#0:|}$"""""{{$$}}"""""; + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("ne") + Await state.AssertSelectedCompletionItem(displayText:="new", isHardSelected:=True) + End Using + End Function + + + + Public Async Function CompletionInRawStringLiteralInterpolation_SingleLine_Partial(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class C +{ + void M(int y) + { + var s = $"""""{$$ + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("ne") + Await state.AssertSelectedCompletionItem(displayText:="new", isHardSelected:=True) + End Using + End Function + + + + Public Async Function CompletionInRawStringLiteralInterpolation_MultiLine(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class C +{ + void M(int y) + { + var s = $""""" + {$$} + """""; + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("ne") + Await state.AssertSelectedCompletionItem(displayText:="new", isHardSelected:=True) + End Using + End Function + + + + Public Async Function CompletionInRawStringLiteralInterpolation_MultiLine_MultiBrace(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class C +{ + void M(int y) + { + var s = ${|#0:|}$""""" + {{$$}} + """""; + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("ne") + Await state.AssertSelectedCompletionItem(displayText:="new", isHardSelected:=True) + End Using + End Function + + + + Public Async Function CompletionInRawStringLiteralInterpolation_MultiLine_Partial(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class C +{ + void M(int y) + { + var s = $""""" + {$$ + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("ne") + Await state.AssertSelectedCompletionItem(displayText:="new", isHardSelected:=True) + End Using + End Function + ' Simulate the situation that some provider (e.g. IntelliCode) provides items with higher match priority that only match case-insensitively. <[Shared]> @@ -9615,5 +9675,222 @@ class C Return Task.CompletedTask End Function End Class + + + Public Async Function TestNonBlockingExpandCompletionViaTyping() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + using $$ + , + extraExportedTypes:={GetType(TestProvider)}.ToList()) + + Dim workspace = state.Workspace + + Dim globalOptions = workspace.GetService(Of IGlobalOptionService) + globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + + state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, True) + + Dim completionService = DirectCast(workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)(), CompletionServiceWithProviders) + Dim provider = completionService.GetTestAccessor().GetAllProviders(ImmutableHashSet(Of String).Empty).OfType(Of TestProvider)().Single() + + ' completion list shouldn't have expand item until we release the checkpoint + state.SendTypeChars("TestUnimp") + Await state.AssertCompletionItemsDoNotContainAny("TestUnimportedItem") + + Dim session = Await state.GetCompletionSession() + Dim expandTask As Task = Nothing + Assert.True(session.Properties.TryGetProperty(Of Task)(CompletionSource.ExpandedItemsTask, expandTask)) + Assert.False(expandTask.IsCompleted) + + ' following up by typing a few more characters each triggers an list update + state.SendTypeChars("o") + Await state.AssertCompletionItemsDoNotContainAny("TestUnimportedItem") + Assert.False(expandTask.IsCompleted) + + Dim uiRender = state.WaitForUIRenderedAsync() + state.SendTypeChars("r") + Await state.AssertCompletionItemsDoNotContainAny("TestUnimportedItem") + Assert.False(expandTask.IsCompleted) + Await uiRender + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=False) + + provider.Checkpoint.Release() + Await expandTask + + ' OK, now the expand task is completed, but we shouldn't have expand item + ' until a refresh is triggered + Await state.AssertCompletionItemsDoNotContainAny("TestUnimportedItem") + Assert.True(expandTask.IsCompleted) + + uiRender = state.WaitForUIRenderedAsync() + state.SendTypeChars("t") + Await state.AssertCompletionItemsContain("TestUnimportedItem", "") + Await state.AssertSelectedCompletionItem("TestUnimportedItem", inlineDescription:="Test.Name.Spaces") + Await uiRender + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) + End Using + End Function + + + Public Async Function TestNonBlockingExpandCompletionViaExpander() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + using $$ + , + extraExportedTypes:={GetType(TestProvider)}.ToList()) + + Dim workspace = state.Workspace + + Dim globalOptions = workspace.GetService(Of IGlobalOptionService) + globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + + state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, True) + + Dim completionService = DirectCast(workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)(), CompletionServiceWithProviders) + Dim provider = completionService.GetTestAccessor().GetAllProviders(ImmutableHashSet(Of String).Empty).OfType(Of TestProvider)().Single() + + ' completion list shouldn't have expand item until we release the checkpoint + state.SendTypeChars("TestUnimp") + Await state.AssertCompletionItemsDoNotContainAny("TestUnimportedItem") + + Dim session = Await state.GetCompletionSession() + Dim expandTask As Task = Nothing + Assert.True(session.Properties.TryGetProperty(Of Task)(CompletionSource.ExpandedItemsTask, expandTask)) + Assert.False(expandTask.IsCompleted) + + ' following up by typing more characters each triggers an list update + Dim uiRender = state.WaitForUIRenderedAsync() + state.SendTypeChars("o") + Await state.AssertCompletionItemsDoNotContainAny("TestUnimportedItem") + Await uiRender + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=False) + Assert.False(expandTask.IsCompleted) + + provider.Checkpoint.Release() + Await expandTask + + ' OK, now the expand task is completed, but we shouldn't have expand item + ' until a refresh is triggered + Await state.AssertCompletionItemsDoNotContainAny("TestUnimportedItem") + Assert.True(expandTask.IsCompleted) + + ' trigger update by using expander + uiRender = state.WaitForUIRenderedAsync() + state.SetCompletionItemExpanderState(isSelected:=True) + Await state.WaitForAsynchronousOperationsAsync() + Await uiRender + + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) + Await state.AssertCompletionItemsContain("TestUnimportedItem", "") + Await state.AssertSelectedCompletionItem("TestUnimportedItem", inlineDescription:="Test.Name.Spaces") + End Using + End Function + + + Public Async Function TestNonBlockingExpandCompletionDoesNotChangeItemOrder() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + $$ + , + extraExportedTypes:={GetType(TestProvider)}.ToList()) + + Dim workspace = state.Workspace + + Dim globalOptions = workspace.GetService(Of IGlobalOptionService) + globalOptions.SetGlobalOption(New OptionKey(CompletionViewOptions.BlockForCompletionItems, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ForceExpandedCompletionIndexCreation), True) + + state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, True) + + Dim completionService = DirectCast(workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)(), CompletionServiceWithProviders) + Dim provider = completionService.GetTestAccessor().GetAllProviders(ImmutableHashSet(Of String).Empty).OfType(Of TestProvider)().Single() + + ' First we enable delay for expand item, and trigger completion with test provider blocked + ' this would ensure completion list don't have expand item until we release the checkpoint + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsDoNotContainAny("TestUnimportedItem") + + Dim session = Await state.GetCompletionSession() + Dim expandTask As Task = Nothing + Assert.True(session.Properties.TryGetProperty(Of Task)(CompletionSource.ExpandedItemsTask, expandTask)) + Assert.False(expandTask.IsCompleted) + + provider.Checkpoint.Release() + Await expandTask + + ' Now delayed expand item task is completed, following up by typing and delete a character to trigger + ' update so the list would contains all items + Dim uiRender = state.WaitForUIRenderedAsync() + state.SendTypeChars("t") + Await state.AssertCompletionItemsContain("TestUnimportedItem", "") + state.SendBackspace() + Await uiRender + state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True) + + ' Get the full list from session where delay happened + Dim list1 = state.GetCompletionItems() + + state.SendEscape() + Await state.AssertNoCompletionSession() + + ' Now disable expand item delay, so intial trigger should contain full list + state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, False) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContain("TestUnimportedItem", "") + + ' Get the full list from session where delay didn't happen + Dim list2 = state.GetCompletionItems() + Assert.Equal(list1.Count, list2.Count) + + ' Two list of items should be identical in order. + For i As Integer = 0 To list1.Count - 1 + Dim item1 = list1(i) + Dim item2 = list2(i) + Assert.Equal(item1, item2) + Next + + End Using + End Function + + + <[Shared]> + + Private Class TestProvider + Inherits CommonCompletionProvider + + Public Checkpoint As Checkpoint = New Checkpoint() + + + + Public Sub New() + End Sub + + Public Overrides Async Function ProvideCompletionsAsync(context As CompletionContext) As Task + Await checkpoint.Task.ConfigureAwait(False) + Dim item = ImportCompletionItem.Create("TestUnimportedItem", 0, "Test.Name.Spaces", Glyph.ClassPublic, "", CompletionItemFlags.CachedAndExpanded, Nothing) + context.AddItem(item) + End Function + + Public Overrides Function IsInsertionTrigger(text As SourceText, characterPosition As Integer, options As CompletionOptions) As Boolean + Return True + End Function + + Friend Overrides ReadOnly Property IsExpandItemProvider As Boolean + Get + Return True + End Get + End Property + + Friend Overrides ReadOnly Property Language As String + Get + Return LanguageNames.CSharp + End Get + End Property + End Class End Class End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DateAndTime.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DateAndTime.vb index 0afd7e1e248a3..f9a203bd1b557 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DateAndTime.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DateAndTime.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Globalization +Imports Microsoft.CodeAnalysis.Test.Utilities.EmbeddedLanguages Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense <[UseExportProvider]> @@ -111,6 +112,146 @@ class c End Using End Function + + Public Async Function ExplicitInvokeDateComment(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("var v = ""G""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvokeTimeComment(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("var v = ""G""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvokeDateTimeComment1(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("var v = ""G""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvokeDateTimeComment2(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("var v = ""G""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvokeStringSyntaxAttribute_Argument(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +using System.Diagnostics.CodeAnalysis; +using System; +class c +{ + void M([StringSyntax(StringSyntaxAttribute.DateTimeFormat)] string p) + { + } + + void goo() + { + M("$$"); + } +} +<%= EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeCSharp %> + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("M(""G"")", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvokeInvalidComment(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( +, showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeCompletionList() + Await state.AssertNoCompletionSession() + End Using + End Function + Public Async Function ExplicitInvoke_OverwriteExisting(showCompletionInArgumentLists As Boolean) As Task Using state = TestStateFactory.CreateCSharpTestState( diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DeclarationName.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DeclarationName.vb new file mode 100644 index 0000000000000..1cf2eb05687be --- /dev/null +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_DeclarationName.vb @@ -0,0 +1,50 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Collections.Immutable +Imports System.Composition +Imports System.Globalization +Imports System.Threading +Imports Microsoft.CodeAnalysis.Completion +Imports Microsoft.CodeAnalysis.Completion.Providers +Imports Microsoft.CodeAnalysis.Completion.Providers.ImportCompletion +Imports Microsoft.CodeAnalysis.CSharp +Imports Microsoft.CodeAnalysis.CSharp.Formatting +Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion +Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.Tags +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion +Imports Microsoft.VisualStudio.Text +Imports Microsoft.VisualStudio.Text.Editor +Imports Microsoft.VisualStudio.Text.Operations +Imports Microsoft.VisualStudio.Text.Projection + +Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense + <[UseExportProvider]> + + Public Class CSharpCompletionCommandHandlerTests_DeclarationName + + Public Async Function SuggestParameterNamesFromExistingOverloads(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +using System.Threading; +public class C +{ + void M(CancellationToken myTok) { } + void M(CancellationToken$$ +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars(" ") + Await state.AssertSelectedCompletionItem(displayText:="myTok", isHardSelected:=False) + End Using + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb index a2f26bef484fb..7e4556adaff71 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb @@ -149,42 +149,242 @@ class C End Using End Function - + - Public Async Function TestFilterOnNamedParameters1(showCompletionInArgumentLists As Boolean) As Task + Public Async Function TestOnIncompleteInvocation(showCompletionInArgumentLists As Boolean) As Task Using state = TestStateFactory.CreateCSharpTestState( - -class C + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + ' We don't have a definite symbol, so default to first + state.SendTypeChars("(") + Await state.AssertSignatureHelpSession() + Assert.Equal({"void Program.F(int i, int j)", "void Program.F(string s, int j, int k)"}, + state.GetSignatureHelpItems().Select(Function(i) i.ToString())) + Await state.AssertSelectedSignatureHelpItem("void Program.F(int i, int j)") + Assert.Equal(2, state.GetSignatureHelpItems().Count) + + ' We have a definite guess (the string overload) + state.SendTypeChars("""""") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("void Program.F(string s, int j, int k)") + Assert.Equal(2, state.GetSignatureHelpItems().Count) + + state.SendTypeChars(", 2") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("void Program.F(string s, int j, int k)") + + state.SendTypeChars(", 3") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("void Program.F(string s, int j, int k)") + + ' Selection becomes invalid + state.SendTypeChars(", 4") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("void Program.F(string s, int j, int k)") + End Using + End Function + + + + Public Async Function TestOnIncompleteInvocation_CommaMatters(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) - , showCompletionInArgumentLists:=showCompletionInArgumentLists) + ' We don't have a definite symbol, so default to first + state.SendTypeChars("(") + Await state.AssertSignatureHelpSession() + Assert.Equal({"void Program.F(int i)", "void Program.F(string s, int j)"}, + state.GetSignatureHelpItems().Select(Function(i) i.ToString())) + Await state.AssertSelectedSignatureHelpItem("void Program.F(int i)") + Assert.Equal(2, state.GetSignatureHelpItems().Count) - state.SendInvokeSignatureHelp() + ' We have a definite guess (the first acceptable overload) + state.SendTypeChars("default") Await state.AssertSignatureHelpSession() - Await state.AssertSelectedSignatureHelpItem("void C.M(int third)") + Await state.AssertSelectedSignatureHelpItem("void Program.F(int i)") Assert.Equal(2, state.GetSignatureHelpItems().Count) - state.SendTypeChars(":") + state.SendTypeChars(",") Await state.AssertSignatureHelpSession() - Await state.AssertSelectedSignatureHelpItem("void C.M(int first, int second)") - Assert.Equal(1, state.GetSignatureHelpItems().Count) + Await state.AssertSelectedSignatureHelpItem("void Program.F(string s, int j)") - ' Now both items are available again, and we're sticking with last selection state.SendBackspace() Await state.AssertSignatureHelpSession() - Await state.AssertSelectedSignatureHelpItem("void C.M(int first, int second)") + Await state.AssertSelectedSignatureHelpItem("void Program.F(int i)") + End Using + End Function + + + + Public Async Function TestOnIncompleteInvocation_WithRef(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + ' We don't have a definite symbol, so default to first + state.SendTypeChars("(") + Await state.AssertSignatureHelpSession() + Assert.Equal({"void Program.F(double d)", "void Program.F(ref int i, int j)"}, + state.GetSignatureHelpItems().Select(Function(i) i.ToString())) + Await state.AssertSelectedSignatureHelpItem("void Program.F(double d)") Assert.Equal(2, state.GetSignatureHelpItems().Count) + + ' We have a definite guess (the overload with ref) + state.SendTypeChars("ref args") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("void Program.F(ref int i, int j)") + + ' Selection becomes invalid + state.SendTypeChars(", 2, 3") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("void Program.F(ref int i, int j)") + End Using + End Function + + + + Public Async Function TestOnIncompleteInvocation_WithArgumentName(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars("(name: 1") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("void Program.F(string name)") + Assert.Equal({"void Program.F(string name)"}, + state.GetSignatureHelpItems().Select(Function(i) i.ToString())) + End Using + End Function + + + + Public Async Function TestOnIncompleteInvocation_WithExtension(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars("(") + Await state.AssertSignatureHelpSession() + Assert.Equal({$"({CSharpFeaturesResources.extension}) void Program.F(string name)", $"({CSharpFeaturesResources.extension}) void Program.F(int i, int j)"}, + state.GetSignatureHelpItems().Select(Function(i) i.ToString())) + Await state.AssertSelectedSignatureHelpItem($"({CSharpFeaturesResources.extension}) void Program.F(string name)") + + state.SendTypeChars("1") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem($"({CSharpFeaturesResources.extension}) void Program.F(int i, int j)") + End Using + End Function + + + + Public Async Function TestOnIncompleteObjectConstruction(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars("(") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("Program(string name)") + Assert.Equal({"Program(string name)", "Program(int i, int j)"}, + state.GetSignatureHelpItems().Select(Function(i) i.ToString())) + + state.SendTypeChars("1") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("Program(int i, int j)") + End Using + End Function + + + + Public Async Function TestOnIncompleteConstructorInitializer(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendTypeChars("(") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("Program(string name)") + Assert.Equal({"Program(string name)", "Program(int i, int j)"}, + state.GetSignatureHelpItems().Select(Function(i) i.ToString())) + + state.SendTypeChars("1") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("Program(int i, int j)") + + state.SendBackspace() + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("Program(int i, int j)") + + state.SendTypeChars("""""") + Await state.AssertSignatureHelpSession() + Await state.AssertSelectedSignatureHelpItem("Program(string name)") End Using End Function @@ -195,7 +395,7 @@ class Program ) - Return workspace.CurrentSolution.GetDocument(workspace.Documents.Single().Id) + Return w.CurrentSolution.GetDocument(w.Documents.Single().Id) End Function)() - Dim threadingContext = DirectCast(document.Project.Solution.Workspace, TestWorkspace).GetService(Of IThreadingContext) + + Dim workspace = DirectCast(document.Project.Solution.Workspace, TestWorkspace) + Dim threadingContext = workspace.GetService(Of IThreadingContext) Dim bufferFactory As ITextBufferFactoryService = DirectCast(document.Project.Solution.Workspace, TestWorkspace).GetService(Of ITextBufferFactoryService) Dim buffer = bufferFactory.CreateTextBuffer() Dim view = CreateMockTextView(buffer) @@ -312,6 +314,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense mockCompletionBroker.Setup(Function(b) b.GetSession(It.IsAny(Of ITextView))).Returns(DirectCast(Nothing, IAsyncCompletionSession)) Dim controller = New Controller( + workspace.GlobalOptions, threadingContext, view.Object, buffer, diff --git a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb index b69e86ed0810b..4b7634dfc4a2a 100644 --- a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb @@ -8,6 +8,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Snippets Imports Microsoft.CodeAnalysis.Tags Imports Microsoft.CodeAnalysis.VisualBasic @@ -1832,9 +1833,9 @@ Class Class1 End Class ) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.EnterKeyBehavior, LanguageNames.VisualBasic, EnterKeyRule.AfterFullyTypedWord))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.VisualBasic), EnterKeyRule.AfterFullyTypedWord) + state.SendTypeChars("System.TimeSpan.FromMin") state.SendReturn() Assert.Equal( @@ -1858,9 +1859,8 @@ Class Class1 End Class ) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.EnterKeyBehavior, LanguageNames.VisualBasic, EnterKeyRule.AfterFullyTypedWord))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.EnterKeyBehavior, LanguageNames.VisualBasic), EnterKeyRule.AfterFullyTypedWord) state.SendTypeChars("System.TimeSpan.FromMinutes") state.SendReturn() @@ -2164,9 +2164,9 @@ Class G End Class ]]>) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.TriggerOnTyping, LanguageNames.VisualBasic, False))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerOnTyping, LanguageNames.VisualBasic), False) + state.SendBackspace() Await state.AssertNoCompletionSession() End Using @@ -2655,9 +2655,8 @@ End Class }]]>, extraExportedTypes:={GetType(MockSnippetInfoService), GetType(SnippetCompletionProvider), GetType(StubVsEditorAdaptersFactoryService)}.ToList()) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.SnippetsBehavior, LanguageNames.VisualBasic, SnippetsRule.AlwaysInclude))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) state.SendTypeChars("Shortcu") Await state.AssertSelectedCompletionItem(displayText:="Shortcut", isHardSelected:=True) @@ -2678,9 +2677,8 @@ End Class }]]>, extraExportedTypes:={GetType(MockSnippetInfoService), GetType(SnippetCompletionProvider), GetType(StubVsEditorAdaptersFactoryService)}.ToList()) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.SnippetsBehavior, LanguageNames.VisualBasic, SnippetsRule.AlwaysInclude))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) state.SendTypeChars("Shortcu") Await state.AssertSelectedCompletionItem(displayText:="Shortcut", isHardSelected:=True) @@ -2702,9 +2700,8 @@ End Class }]]>, extraExportedTypes:={GetType(MockSnippetInfoService), GetType(SnippetCompletionProvider), GetType(StubVsEditorAdaptersFactoryService)}.ToList()) - Dim workspace = state.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(CompletionOptions.Metadata.SnippetsBehavior, LanguageNames.VisualBasic, SnippetsRule.AlwaysInclude))) + state.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) state.SendInvokeCompletionList() Await state.AssertCompletionItemsContainAll("x", "Shortcut") diff --git a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests_DateAndTime.vb b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests_DateAndTime.vb index 92a21f677f648..ca21eef22f9ac 100644 --- a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests_DateAndTime.vb +++ b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests_DateAndTime.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Globalization +Imports Microsoft.CodeAnalysis.Test.Utilities.EmbeddedLanguages Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense <[UseExportProvider]> @@ -26,6 +27,52 @@ end class End Using End Function + + Public Async Function ExplicitInvoke_LanguageComment() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + ) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("dim d = ""G""", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + Public Async Function ExplicitInvoke_StringSyntaxAttribute_Argument() As Task + Using state = TestStateFactory.CreateVisualBasicTestState( + p as string) + end sub +end class +]]> + <%= EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeVBXml %> + ) + + state.SendInvokeCompletionList() + Await state.AssertSelectedCompletionItem("G", inlineDescription:=FeaturesResources.general_long_date_time) + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("M(""G"")", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + Public Async Function ExplicitInvoke_OverwriteExisting() As Task Using state = TestStateFactory.CreateVisualBasicTestState( diff --git a/src/EditorFeatures/Test2/KeywordHighlighting/AbstractKeywordHighlightingTests.vb b/src/EditorFeatures/Test2/KeywordHighlighting/AbstractKeywordHighlightingTests.vb index a66c75b5854e4..5518144928633 100644 --- a/src/EditorFeatures/Test2/KeywordHighlighting/AbstractKeywordHighlightingTests.vb +++ b/src/EditorFeatures/Test2/KeywordHighlighting/AbstractKeywordHighlightingTests.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.Editor.Shared.Options Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.Tagging Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.TestHooks Imports Microsoft.VisualStudio.Text diff --git a/src/EditorFeatures/Test2/NavigableSymbols/NavigableSymbolsTest.vb b/src/EditorFeatures/Test2/NavigableSymbols/NavigableSymbolsTest.vb index f8c3742379239..20b929574d18f 100644 --- a/src/EditorFeatures/Test2/NavigableSymbols/NavigableSymbolsTest.vb +++ b/src/EditorFeatures/Test2/NavigableSymbols/NavigableSymbolsTest.vb @@ -117,7 +117,7 @@ End Class" Private Shared Function ExtractSymbol(workspace As TestWorkspace, position As Integer) As Task(Of INavigableSymbol) Dim threadingContext = workspace.ExportProvider.GetExportedValue(Of IThreadingContext)() - Dim presenter = New MockStreamingFindUsagesPresenter(Sub() Return) + Dim presenter = New MockStreamingFindUsagesPresenter(workspace.GlobalOptions, Sub() Return) Dim listenerProvider = workspace.ExportProvider.GetExportedValue(Of IAsynchronousOperationListenerProvider) Dim service = New NavigableSymbolService(workspace.ExportProvider.GetExportedValue(Of IUIThreadOperationExecutor)(), threadingContext, presenter, listenerProvider) Dim view = workspace.Documents.First().GetTextView() diff --git a/src/EditorFeatures/Test2/Peek/PeekTests.vb b/src/EditorFeatures/Test2/Peek/PeekTests.vb index e8155757d9549..9e60817ccd6fd 100644 --- a/src/EditorFeatures/Test2/Peek/PeekTests.vb +++ b/src/EditorFeatures/Test2/Peek/PeekTests.vb @@ -184,6 +184,45 @@ End Module End Sub + + Public Sub TestFileMapping() + Using workspace = CreateTestWorkspace( + + + + + + ) + Dim result = GetPeekResultCollection(workspace) + + Assert.Equal(1, result.Items.Count) + result.AssertNavigatesToIdentifier(0, "Identifier") + End Using + End Sub + Private Shared Function CreateTestWorkspace(element As XElement) As TestWorkspace Return TestWorkspace.Create(element, composition:=EditorTestCompositions.EditorFeaturesWpf) End Function diff --git a/src/EditorFeatures/Test2/Rename/DashboardTests.vb b/src/EditorFeatures/Test2/Rename/DashboardTests.vb index a65fb68345e1a..eee1bf947cd4f 100644 --- a/src/EditorFeatures/Test2/Rename/DashboardTests.vb +++ b/src/EditorFeatures/Test2/Rename/DashboardTests.vb @@ -5,8 +5,8 @@ Imports System.Threading Imports System.Threading.Tasks Imports Microsoft.CodeAnalysis.Editor.Implementation.InlineRename +Imports Microsoft.CodeAnalysis.InlineRename Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.Remote.Testing Imports Microsoft.CodeAnalysis.Rename Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename @@ -15,8 +15,6 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename Public Async Function RenameWithNoOverload(host As RenameTestHost) As Task - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameOverloads, True) Await VerifyDashboard( ( @@ -37,14 +35,12 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename ), host:=host, newName:="", searchResultText:=EditorFeaturesResources.Rename_will_update_1_reference_in_1_file, - changedOptionSet:=changingOptions) + renameOverloads:=True) End Function Public Async Function RenameWithOverload(host As RenameTestHost) As Task - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameOverloads, True) Await VerifyDashboard( ( @@ -70,15 +66,13 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename newName:="", searchResultText:=String.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_file, 2), hasRenameOverload:=True, - changedOptionSet:=changingOptions) + renameOverloads:=True) End Function Public Async Function RenameWithInvalidOverload(host As RenameTestHost) As Task - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameOverloads, True) Await VerifyDashboard( @@ -99,7 +93,7 @@ class Program host:=host, newName:="Bar", searchResultText:=String.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_file, 2), - changedOptionSet:=changingOptions, + renameOverloads:=True, hasRenameOverload:=True, unresolvableConflictText:=String.Format(EditorFeaturesResources._0_unresolvable_conflict_s, 1), severity:=DashboardSeverity.Error) @@ -129,10 +123,6 @@ class AttributeAttribute : System.Attribute { } Public Async Function RenameWithOverloadAndInStringsAndComments(host As RenameTestHost) As Task - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameOverloads, True) - changingOptions.Add(RenameOptions.RenameInStrings, True) - changingOptions.Add(RenameOptions.RenameInComments, True) Await VerifyDashboard( ( @@ -161,15 +151,15 @@ class AttributeAttribute : System.Attribute { } newName:="", searchResultText:=String.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_file, 5), hasRenameOverload:=True, - changedOptionSet:=changingOptions) + renameOverloads:=True, + renameInStrings:=True, + renameInComments:=True) End Function Public Async Function RenameInComments(host As RenameTestHost) As Task - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameInComments, True) Await VerifyDashboard( ( @@ -201,15 +191,13 @@ class $$Program ), host:=host, newName:="P", searchResultText:=String.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_file, 6), - changedOptionSet:=changingOptions) + renameInComments:=True) End Function Public Async Function RenameInStrings(host As RenameTestHost) As Task - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameInStrings, True) Await VerifyDashboard( ( @@ -241,16 +229,13 @@ class $$Program ), host:=host, newName:="P", searchResultText:=String.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_file, 2), - changedOptionSet:=changingOptions) + renameInStrings:=True) End Function Public Async Function RenameInCommentsAndStrings(host As RenameTestHost) As Task - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameInComments, True) - changingOptions.Add(RenameOptions.RenameInStrings, True) Await VerifyDashboard( ( @@ -282,7 +267,8 @@ class $$Program ), host:=host, newName:="P", searchResultText:=String.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_file, 7), - changedOptionSet:=changingOptions) + renameInStrings:=True, + renameInComments:=True) End Function @@ -512,8 +498,6 @@ class C Public Async Function RenameWithNameof_FromDefinition_WithRenameOverloads_Cascading(host As RenameTestHost) As Task - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameOverloads, True) Await VerifyDashboard( ( @@ -542,7 +526,7 @@ class D : B ), host:=host, newName:="Mo", searchResultText:=String.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_file, 5), - changedOptionSet:=changingOptions, + renameOverloads:=True, hasRenameOverload:=True) End Function @@ -553,13 +537,22 @@ class D : B host As RenameTestHost, Optional hasRenameOverload As Boolean = False, Optional isRenameOverloadsEditable As Boolean = True, - Optional changedOptionSet As Dictionary(Of OptionKey, Object) = Nothing, + Optional renameOverloads As Boolean = False, + Optional renameInStrings As Boolean = False, + Optional renameInComments As Boolean = False, + Optional renameFile As Boolean = False, Optional resolvableConflictText As String = Nothing, Optional unresolvableConflictText As String = Nothing, Optional severity As DashboardSeverity = DashboardSeverity.None ) As Tasks.Task Using workspace = CreateWorkspaceWithWaiter(test, host) + Dim globalOptions = workspace.GetService(Of IGlobalOptionService)() + globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameOverloads), renameOverloads) + globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameInStrings), renameInStrings) + globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameInComments), renameInComments) + globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameFile), renameFile) + Dim cursorDocument = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue) Dim cursorPosition = cursorDocument.CursorPosition.Value @@ -575,16 +568,6 @@ class D : B d.GetTextView() Next - Dim optionSet = workspace.Options - - If changedOptionSet IsNot Nothing Then - For Each entry In changedOptionSet - optionSet = optionSet.WithChangedOption(entry.Key, entry.Value) - Next - End If - - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(optionSet)) - Dim sessionInfo = renameService.StartInlineSession( document, document.GetSyntaxTreeAsync().Result.GetRoot().FindToken(cursorPosition).Span, CancellationToken.None) @@ -637,8 +620,6 @@ class D : B Public Async Function RenameWithReferenceInUnchangeableDocument(host As RenameTestHost) As Task - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameOverloads, True) Await VerifyDashboard( ( @@ -660,7 +641,7 @@ class D : B ), host:=host, newName:="C", searchResultText:=EditorFeaturesResources.Rename_will_update_1_reference_in_1_file, - changedOptionSet:=changingOptions) + renameOverloads:=True) End Function End Class End Namespace diff --git a/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb b/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb index 2b3417902bae8..ba8115be3ea92 100644 --- a/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb +++ b/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb @@ -6,12 +6,13 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeRefactorings Imports Microsoft.CodeAnalysis.Editor.Host +Imports Microsoft.CodeAnalysis.Editor.Implementation.InlineRename Imports Microsoft.CodeAnalysis.Editor.UnitTests.RenameTracking Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.InlineRename Imports Microsoft.CodeAnalysis.IntroduceVariable Imports Microsoft.CodeAnalysis.Notification Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.Remote.Testing Imports Microsoft.CodeAnalysis.Rename Imports Microsoft.CodeAnalysis.Shared.Utilities Imports Microsoft.VisualStudio.Text @@ -124,9 +125,8 @@ class [|Test1$$|] , host) - Dim options = workspace.CurrentSolution.Options - workspace.TryApplyChanges( - workspace.CurrentSolution.WithOptions(options.WithChangedOption(RenameOptions.RenameFile, True))) + Dim globalOptions = workspace.GetService(Of IGlobalOptionService)() + globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameFile), True) Dim session = StartSession(workspace) @@ -244,12 +244,12 @@ class Deconstructable Optional renameInComments As Boolean = False, Optional renameFile As Boolean = False, Optional fileToRename As DocumentId = Nothing) As Task - Dim optionSet = workspace.Options - optionSet = optionSet.WithChangedOption(RenameOptions.RenameOverloads, renameOverloads) - optionSet = optionSet.WithChangedOption(RenameOptions.RenameInStrings, renameInStrings) - optionSet = optionSet.WithChangedOption(RenameOptions.RenameInComments, renameInComments) - optionSet = optionSet.WithChangedOption(RenameOptions.RenameFile, renameFile) - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(optionSet)) + + Dim globalOptions = workspace.GetService(Of IGlobalOptionService)() + globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameOverloads), renameOverloads) + globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameInStrings), renameInStrings) + globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameInComments), renameInComments) + globalOptions.SetGlobalOption(New OptionKey(InlineRenameSessionOptionsStorage.RenameFile), renameFile) Dim session = StartSession(workspace) @@ -2102,7 +2102,7 @@ class [|C|] Dim session = StartSession(workspace) session.ApplyReplacementText("Example", True) - session.RefreshRenameSessionWithOptionsChanged(RenameOptions.RenameInComments, True) + session.RefreshRenameSessionWithOptionsChanged(New SymbolRenameOptions(RenameInComments:=True)) session.Commit() diff --git a/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb b/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb index 22c182bb65c00..5dbe3fa3e2a31 100644 --- a/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb +++ b/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb @@ -50,7 +50,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename workspaceXml As XElement, renameTo As String, host As RenameTestHost, - Optional changedOptionSet As Dictionary(Of OptionKey, Object) = Nothing, + Optional renameOptions As SymbolRenameOptions = Nothing, Optional expectFailure As Boolean = False, Optional sourceGenerator As ISourceGenerator = Nothing) As RenameEngineResult @@ -83,15 +83,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename AssertEx.Fail("The symbol touching the $$ could not be found.") End If - Dim optionSet = workspace.Options - - If changedOptionSet IsNot Nothing Then - For Each entry In changedOptionSet - optionSet = optionSet.WithChangedOption(entry.Key, entry.Value) - Next - End If - - Dim result = GetConflictResolution(renameTo, workspace.CurrentSolution, symbol, optionSet, host) + Dim result = GetConflictResolution(renameTo, workspace.CurrentSolution, symbol, renameOptions, host) If expectFailure Then Assert.NotNull(result.ErrorMessage) @@ -120,11 +112,9 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename renameTo As String, solution As Solution, symbol As ISymbol, - optionSet As OptionSet, + renameOptions As SymbolRenameOptions, host As RenameTestHost) As ConflictResolution - Dim renameOptions = RenameOptionSet.From(solution, optionSet) - If host = RenameTestHost.OutOfProcess_SplitCall Then ' This tests that each portion of rename can properly marshal to/from the OOP process. It validates ' features that need to call each part independently and operate on the intermediary values. diff --git a/src/EditorFeatures/Test2/Rename/RenameEngineTests.vb b/src/EditorFeatures/Test2/Rename/RenameEngineTests.vb index 3f958fb58f112..6e108428b9cc5 100644 --- a/src/EditorFeatures/Test2/Rename/RenameEngineTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameEngineTests.vb @@ -571,8 +571,7 @@ class {|unresolve3:$$D|} // Rename to C Public Sub RenameOverloadCSharp(host As RenameTestHost) - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameOverloads, True) + Dim renameOptions = New SymbolRenameOptions(RenameOverloads:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -601,15 +600,14 @@ class {|unresolve3:$$D|} // Rename to C } - , host:=host, renameTo:="BarBaz", changedOptionSet:=changingOptions) + , host:=host, renameTo:="BarBaz", renameOptions:=renameOptions) End Using End Sub Public Sub RenameOverloadVisualBasic(host As RenameTestHost) - Dim changingOptions = New Dictionary(Of OptionKey, Object)() - changingOptions.Add(RenameOptions.RenameOverloads, True) + Dim renameOptions = New SymbolRenameOptions(RenameOverloads:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -641,7 +639,7 @@ class {|unresolve3:$$D|} // Rename to C End Class - , host:=host, renameTo:="BarBaz", changedOptionSet:=changingOptions) + , host:=host, renameTo:="BarBaz", renameOptions:=renameOptions) End Using End Sub @@ -6089,9 +6087,7 @@ End Class Public Sub RenameInStrings(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, False) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6110,7 +6106,7 @@ End Module ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """NewProgram NewProgram!""") End Using @@ -6119,9 +6115,7 @@ End Module Public Sub RenameInStrings_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, False) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6142,7 +6136,7 @@ public class [|$$Program|] ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """NewProgram NewProgram!""") End Using @@ -6151,9 +6145,7 @@ public class [|$$Program|] Public Sub RenameInComments(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, False) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6172,7 +6164,7 @@ End Module ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " NewProgram PROGRAM! NewProgram!") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment2", "' NewProgram PROGRAM! NewProgram!") @@ -6183,9 +6175,7 @@ End Module Public Sub RenameInComments_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, False) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6205,7 +6195,7 @@ public class [|$$Program|] ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " NewProgram PROGRAM! NewProgram!") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment2", "// NewProgram PROGRAM! NewProgram!") @@ -6215,9 +6205,7 @@ public class [|$$Program|] Public Sub RenameInComments_XmlName(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, False) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6230,7 +6218,7 @@ End Class ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment", "NewProgram") End Using @@ -6239,9 +6227,6 @@ End Class Public Sub RenameInComments_XmlName2(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, False) - renamingOptions.Add(RenameOptions.RenameInComments, False) Using result = RenameEngineResult.Create(_outputHelper, @@ -6256,7 +6241,7 @@ End Class ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram") Assert.Equal(1, result.ConflictResolution.RelatedLocations.Count) End Using @@ -6265,9 +6250,7 @@ End Class Public Sub RenameInComments_XmlName_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, False) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6281,7 +6264,7 @@ public class [|$$Program|] ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment", "NewProgram") End Using @@ -6290,9 +6273,6 @@ public class [|$$Program|] Public Sub RenameInComments_XmlName_CSharp2(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, False) - renamingOptions.Add(RenameOptions.RenameInComments, False) Using result = RenameEngineResult.Create(_outputHelper, @@ -6309,7 +6289,7 @@ public class [|$$Program|] ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram") Assert.Equal(1, result.ConflictResolution.RelatedLocations.Count) End Using @@ -6318,9 +6298,7 @@ public class [|$$Program|] Public Sub RenameInStringsAndComments(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6340,7 +6318,7 @@ End Module ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """NewProgram NewProgram!""") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " NewProgram PROGRAM! NewProgram!") @@ -6352,9 +6330,7 @@ End Module Public Sub RenameInStringsAndComments_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6374,7 +6350,7 @@ public class [|$$Program|] ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """NewProgram NewProgram!""") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " NewProgram PROGRAM! NewProgram!") @@ -6385,9 +6361,7 @@ public class [|$$Program|] Public Sub RenameInStringsAndComments_SmallerReplacementString(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6406,7 +6380,7 @@ End Module ]]> - , host:=host, renameTo:="P", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="P", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """P P!""") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " P PROGRAM! P!") @@ -6418,9 +6392,7 @@ End Module Public Sub RenameInStringsAndComments_SmallerReplacementString_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6440,7 +6412,7 @@ public class [|$$Program|] ]]> - , host:=host, renameTo:="P", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="P", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """P P!""") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " P PROGRAM! P!") @@ -6451,9 +6423,7 @@ public class [|$$Program|] Public Sub RenameInStringsAndComments_AnotherSourceFile(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6477,7 +6447,7 @@ End Class ]]> - , host:=host, renameTo:="P", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="P", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """P P!""") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " P PROGRAM! P!") @@ -6489,9 +6459,7 @@ End Class Public Sub RenameInStringsAndComments_AnotherSourceFile_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6517,7 +6485,7 @@ public class AnotherFile ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """NewProgram NewProgram!""") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " NewProgram PROGRAM! NewProgram!") @@ -6528,9 +6496,7 @@ public class AnotherFile Public Sub RenameInStringsAndComments_AnotherProject(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6560,7 +6526,7 @@ End Class ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """NewProgram NewProgram!""") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " NewProgram PROGRAM! NewProgram!") @@ -6572,9 +6538,7 @@ End Class Public Sub RenameInStringsAndComments_AnotherProject_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6605,7 +6569,7 @@ public class AnotherFile ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """NewProgram NewProgram!""") result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", " NewProgram PROGRAM! NewProgram!") @@ -6616,9 +6580,7 @@ public class AnotherFile Public Sub RenameInStringsAndComments_AnotherProject2(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6676,7 +6638,7 @@ End Class ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) Assert.Equal(1, result.ConflictResolution.RelatedLocations.Count) End Using @@ -6685,9 +6647,7 @@ End Class Public Sub RenameInStringsAndComments_AnotherProject_CSharp2(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6744,7 +6704,7 @@ public class NotReferencingProject ]]> - , host:=host, renameTo:="NewProgram", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="NewProgram", renameOptions:=renameOptions) Assert.Equal(1, result.ConflictResolution.RelatedLocations.Count) End Using @@ -6753,9 +6713,7 @@ public class NotReferencingProject Public Sub RenameInStringsAndComments_WithResolvableConflict(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6783,7 +6741,7 @@ End Class ]]> - , host:=host, renameTo:="Bar", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="Bar", renameOptions:=renameOptions) result.AssertLabeledSpansAre("stmt1", "Call Global.M.Bar(""1"")", RelatedLocationType.ResolvedReferenceConflict) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInComment1", "' Rename Bar to Bar") @@ -6796,9 +6754,7 @@ End Class Public Sub RenameInStringsAndComments_WithResolvableConflict_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6820,7 +6776,7 @@ End Class ]]> - , host:=host, renameTo:="goo", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="goo", renameOptions:=renameOptions) result.AssertLabeledSpansAre("stmt1", "this.goo = goo;", RelatedLocationType.NoConflict) result.AssertLabeledSpansAre("stmt2", "this.goo = goo;", RelatedLocationType.ResolvedNonReferenceConflict) @@ -6832,9 +6788,7 @@ End Class Public Sub RenameInStringsAndComments_WithUnresolvableConflict(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6852,7 +6806,7 @@ End Module ]]> - , host:=host, renameTo:="Bar", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="Bar", renameOptions:=renameOptions) result.AssertLabeledSpansAre("Conflict", type:=RelatedLocationType.UnresolvedConflict) result.AssertLabeledSpansInStringsAndCommentsAre("RenameInString", """Bar Bar!""") @@ -6864,9 +6818,7 @@ End Module Public Sub RenameInStringsAndComments_WithUnresolvableConflict_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameInStrings, True) - renamingOptions.Add(RenameOptions.RenameInComments, True) + Dim renameOptions = New SymbolRenameOptions(RenameInStrings:=True, RenameInComments:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6882,7 +6834,7 @@ class {|Conflict:goo|} ]]> - , host:=host, renameTo:="goo", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="goo", renameOptions:=renameOptions) result.AssertLabeledSpansAre("Conflict", type:=RelatedLocationType.UnresolvedConflict) @@ -6943,8 +6895,7 @@ class C Public Sub RenameMethodWithNameof_WithOverloads_WithRenameOverloadsOption_CSharp(host As RenameTestHost) - Dim renamingOptions = New Dictionary(Of OptionKey, Object)() - renamingOptions.Add(RenameOptions.RenameOverloads, True) + Dim renameOptions = New SymbolRenameOptions(RenameOverloads:=True) Using result = RenameEngineResult.Create(_outputHelper, @@ -6963,7 +6914,7 @@ class C ]]> - , host:=host, renameTo:="Mo", changedOptionSet:=renamingOptions) + , host:=host, renameTo:="Mo", renameOptions:=renameOptions) End Using End Sub diff --git a/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb b/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb index 5685ad4f6db0d..5c14bd035224c 100644 --- a/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameTagProducerTests.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis.Editor.Implementation.InlineRename Imports Microsoft.CodeAnalysis.Editor.Implementation.InlineRename.HighlightTags Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Rename Imports Microsoft.CodeAnalysis.Text.Shared.Extensions Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor @@ -1674,10 +1675,11 @@ static class E Dim location = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value Dim textBuffer = workspace.Documents(0).GetTextBuffer() Dim session = StartSession(workspace) - session.RefreshRenameSessionWithOptionsChanged(CodeAnalysis.Rename.RenameOptions.RenameInComments, newValue:=True) + + session.RefreshRenameSessionWithOptionsChanged(New SymbolRenameOptions(RenameInComments:=True)) Await WaitForRename(workspace) - session.RefreshRenameSessionWithOptionsChanged(CodeAnalysis.Rename.RenameOptions.RenameInComments, newValue:=False) + session.RefreshRenameSessionWithOptionsChanged(New SymbolRenameOptions()) Await WaitForRename(workspace) textBuffer.Replace(New Span(location, 3), "Bar") diff --git a/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb b/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb index 0e116da62d27f..afa6431bae7dc 100644 --- a/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb +++ b/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb @@ -13,6 +13,7 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Shared.TestHooks +Imports Microsoft.CodeAnalysis.Rename Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.Text.Shared.Extensions Imports Microsoft.VisualStudio.Text @@ -46,7 +47,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename Dim renameService = workspace.GetService(Of IInlineRenameService)() Dim sessionInfo = GetSessionInfo(workspace) - Return DirectCast(renameService.StartInlineSession(sessionInfo.document, sessionInfo.textSpan).Session, InlineRenameSession) + Return DirectCast(renameService.StartInlineSession(sessionInfo.document, sessionInfo.textSpan, CancellationToken.None).Session, InlineRenameSession) End Function Public Sub AssertTokenRenamable(workspace As TestWorkspace) diff --git a/src/EditorFeatures/TestUtilities/Classification/AbstractClassifierTests.cs b/src/EditorFeatures/TestUtilities/Classification/AbstractClassifierTests.cs index 658a581645e97..1001e756a9598 100644 --- a/src/EditorFeatures/TestUtilities/Classification/AbstractClassifierTests.cs +++ b/src/EditorFeatures/TestUtilities/Classification/AbstractClassifierTests.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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; @@ -19,6 +17,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Roslyn.Utilities; +using Xunit; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Classification { @@ -27,7 +26,7 @@ public abstract class AbstractClassifierTests { protected AbstractClassifierTests() { } - protected abstract Task> GetClassificationSpansAsync(string text, TextSpan span, ParseOptions parseOptions, TestHost testHost); + protected abstract Task> GetClassificationSpansAsync(string text, TextSpan span, ParseOptions? parseOptions, TestHost testHost); protected abstract string WrapInClass(string className, string code); protected abstract string WrapInExpression(string code); @@ -40,12 +39,31 @@ protected async Task TestAsync( string code, string allCode, TestHost testHost, - ParseOptions parseOptions, + ParseOptions? parseOptions, params FormattedClassification[] expected) { - var start = allCode.IndexOf(code, StringComparison.Ordinal); - var length = code.Length; - var span = new TextSpan(start, length); + TextSpan span; + if (code != allCode) + { + var start = allCode.IndexOf(code, StringComparison.Ordinal); + var length = code.Length; + span = new TextSpan(start, length); + } + else + { + MarkupTestFile.GetSpans(allCode, out var rewrittenCode, out ImmutableArray spans); + Assert.True(spans.Length < 2); + if (spans.Length == 1) + { + allCode = rewrittenCode; + span = spans.Single(); + } + else + { + span = new TextSpan(0, allCode.Length); + } + } + var actual = await GetClassificationSpansAsync(allCode, span, parseOptions, testHost); var actualOrdered = actual.OrderBy((t1, t2) => t1.TextSpan.Start - t2.TextSpan.Start); @@ -254,8 +272,8 @@ protected static async Task> GetSemanticClassific protected static async Task> GetSyntacticClassificationsAsync(Document document, TextSpan span) { - var root = await document.GetSyntaxRootAsync(); - var service = document.GetLanguageService(); + var root = await document.GetRequiredSyntaxRootAsync(CancellationToken.None); + var service = document.GetRequiredLanguageService(); using var _ = ArrayBuilder.GetInstance(out var results); service.AddSyntacticClassifications(root, span, results, CancellationToken.None); diff --git a/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs b/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs index 8a023df776fb1..ed0330d10409c 100644 --- a/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs +++ b/src/EditorFeatures/TestUtilities/Classification/FormattedClassification.cs @@ -46,6 +46,14 @@ public override string ToString() return "Regex." + $"{type}(\"{Text}\")"; } + if (ClassificationName.StartsWith("json")) + { + var remainder = ClassificationName.Substring("json - ".Length); + var parts = remainder.Split(' '); + var type = string.Join("", parts.Select(Capitalize)); + return "Json." + $"{type}(\"{Text}\")"; + } + switch (ClassificationName) { case "punctuation": diff --git a/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.Json.cs b/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.Json.cs new file mode 100644 index 0000000000000..15c761ad5d80b --- /dev/null +++ b/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.Json.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.Diagnostics; +using Microsoft.CodeAnalysis.Classification; + +namespace Microsoft.CodeAnalysis.Editor.UnitTests.Classification +{ + public static partial class FormattedClassifications + { + public static class Json + { + [DebuggerStepThrough] + public static FormattedClassification Array(string value) => New(value, ClassificationTypeNames.JsonArray); + + [DebuggerStepThrough] + public static FormattedClassification Object(string value) => New(value, ClassificationTypeNames.JsonObject); + + [DebuggerStepThrough] + public static FormattedClassification PropertyName(string value) => New(value, ClassificationTypeNames.JsonPropertyName); + + [DebuggerStepThrough] + public static FormattedClassification Punctuation(string value) => New(value, ClassificationTypeNames.JsonPunctuation); + + [DebuggerStepThrough] + public static FormattedClassification Number(string value) => New(value, ClassificationTypeNames.JsonNumber); + + [DebuggerStepThrough] + public static FormattedClassification Operator(string value) => New(value, ClassificationTypeNames.JsonOperator); + + [DebuggerStepThrough] + public static FormattedClassification Keyword(string value) => New(value, ClassificationTypeNames.JsonKeyword); + + [DebuggerStepThrough] + public static FormattedClassification ConstructorName(string value) => New(value, ClassificationTypeNames.JsonConstructorName); + + [DebuggerStepThrough] + public static FormattedClassification Comment(string value) => New(value, ClassificationTypeNames.JsonComment); + + [DebuggerStepThrough] + public static FormattedClassification Text(string value) => New(value, ClassificationTypeNames.JsonText); + + [DebuggerStepThrough] + public static FormattedClassification String(string value) => New(value, ClassificationTypeNames.JsonString); + } + } +} diff --git a/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.RegexTypes.cs b/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.Regex.cs similarity index 99% rename from src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.RegexTypes.cs rename to src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.Regex.cs index 09f2b8e6c6013..727048ea17143 100644 --- a/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.RegexTypes.cs +++ b/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.Regex.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Diagnostics; using Microsoft.CodeAnalysis.Classification; diff --git a/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.cs b/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.cs index 0a05fc8cdad27..f3bb35e15a5da 100644 --- a/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.cs +++ b/src/EditorFeatures/TestUtilities/Classification/FormattedClassifications.cs @@ -110,6 +110,10 @@ public static FormattedClassification Escape(string text) public static FormattedClassification Keyword(string text) => New(text, ClassificationTypeNames.Keyword); + [DebuggerStepThrough] + public static FormattedClassification PunctuationText(string text) + => New(text, ClassificationTypeNames.Punctuation); + [DebuggerStepThrough] public static FormattedClassification ControlKeyword(string text) => New(text, ClassificationTypeNames.ControlKeyword); diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractArgumentProviderTests`1.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractArgumentProviderTests`1.cs index e57bde7378c16..ac23d353e45b4 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractArgumentProviderTests`1.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractArgumentProviderTests`1.cs @@ -3,18 +3,21 @@ // 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.Completion; using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.Composition; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Test.Utilities.Completion { @@ -39,12 +42,15 @@ private protected ReferenceCountedDisposable GetOrCreateWorks internal abstract Type GetArgumentProviderType(); + protected abstract (SyntaxNode argumentList, ImmutableArray arguments) GetArgumentList(SyntaxToken token); + protected virtual OptionSet WithChangedOptions(OptionSet options) => options; private protected async Task VerifyDefaultValueAsync( string markup, string? expectedDefaultValue, - string? previousDefaultValue = null) + string? previousDefaultValue = null, + OptionsCollection? options = null) { using var workspaceFixture = GetOrCreateWorkspaceFixture(); @@ -52,7 +58,14 @@ private protected async Task VerifyDefaultValueAsync( var code = workspaceFixture.Target.Code; var position = workspaceFixture.Target.Position; - workspace.SetOptions(WithChangedOptions(workspace.Options)); + var changedOptions = WithChangedOptions(workspace.Options); + if (options is not null) + { + foreach (var option in options) + changedOptions = changedOptions.WithChangedOption(option.Key, option.Value); + } + + workspace.SetOptions(changedOptions); var document = workspaceFixture.Target.UpdateDocument(code, SourceCodeKind.Regular); @@ -60,17 +73,59 @@ private protected async Task VerifyDefaultValueAsync( Assert.IsType(GetArgumentProviderType(), provider); var root = await document.GetRequiredSyntaxRootAsync(CancellationToken.None); - var token = root.FindToken(position - 2); + var documentOptions = await document.GetOptionsAsync(CancellationToken.None); var semanticModel = await document.GetRequiredSemanticModelAsync(CancellationToken.None); - var symbolInfo = semanticModel.GetSymbolInfo(token.GetRequiredParent(), CancellationToken.None); - var target = symbolInfo.Symbol ?? symbolInfo.CandidateSymbols.Single(); - Contract.ThrowIfNull(target); + var parameter = GetParameterSymbolInfo(workspace, semanticModel, root, position, CancellationToken.None); + Contract.ThrowIfNull(parameter); - var parameter = target.GetParameters().Single(); - var context = new ArgumentContext(provider, semanticModel, position, parameter, previousDefaultValue, CancellationToken.None); + var context = new ArgumentContext(provider, documentOptions, semanticModel, position, parameter, previousDefaultValue, CancellationToken.None); await provider.ProvideArgumentAsync(context); Assert.Equal(expectedDefaultValue, context.DefaultValue); } + + private IParameterSymbol GetParameterSymbolInfo(Workspace workspace, SemanticModel semanticModel, SyntaxNode root, int position, CancellationToken cancellationToken) + { + var token = root.FindToken(position); + var (argumentList, arguments) = GetArgumentList(token); + var symbols = semanticModel.GetSymbolInfo(argumentList.GetRequiredParent(), cancellationToken).GetAllSymbols(); + + // if more than one symbol is found, filter to only include symbols with a matching number of arguments + if (symbols.Length > 1) + { + symbols = symbols.WhereAsArray( + symbol => + { + var parameters = symbol.GetParameters(); + if (arguments.Length < GetMinimumArgumentCount(parameters)) + return false; + + if (arguments.Length > GetMaximumArgumentCount(parameters)) + return false; + + return true; + }); + } + + var symbol = symbols.Single(); + var parameters = symbol.GetParameters(); + + var syntaxFacts = workspace.Services.GetLanguageServices(root.Language).GetRequiredService(); + Contract.ThrowIfTrue(arguments.Any(argument => syntaxFacts.IsNamedArgument(argument)), "Named arguments are not currently supported by this test."); + Contract.ThrowIfTrue(parameters.Any(parameter => parameter.IsParams), "'params' parameters are not currently supported by this test."); + + var index = arguments.Any() + ? arguments.IndexOf(arguments.Single(argument => argument.FullSpan.Start <= position && argument.FullSpan.End >= position)) + : 0; + + return parameters[index]; + + // Local functions + static int GetMinimumArgumentCount(ImmutableArray parameters) + => parameters.Count(parameter => !parameter.IsOptional && !parameter.IsParams); + + static int GetMaximumArgumentCount(ImmutableArray parameters) + => parameters.Any(parameter => parameter.IsParams) ? int.MaxValue : parameters.Length; + } } } diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index eb645347926dc..446013410a669 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs @@ -48,8 +48,7 @@ public abstract class AbstractCompletionProviderTests : TestB protected bool? TargetTypedCompletionFilterFeatureFlag { get; set; } protected bool? TypeImportCompletionFeatureFlag { get; set; } protected bool? ShowImportCompletionItemsOptionValue { get; set; } - protected int? TimeoutInMilliseconds { get; set; } - protected bool? IsExpandedCompletion { get; set; } + protected bool? ForceExpandedCompletionIndexCreation { get; set; } protected bool? HideAdvancedMembers { get; set; } protected bool? ShowNameSuggestions { get; set; } @@ -74,11 +73,8 @@ private CompletionOptions GetCompletionOptions() if (ShowImportCompletionItemsOptionValue.HasValue) options = options with { ShowItemsFromUnimportedNamespaces = ShowImportCompletionItemsOptionValue.Value }; - if (TimeoutInMilliseconds.HasValue) - options = options with { TimeoutInMillisecondsForExtensionMethodImportCompletion = TimeoutInMilliseconds.Value }; - - if (IsExpandedCompletion.HasValue) - options = options with { IsExpandedCompletion = IsExpandedCompletion.Value }; + if (ForceExpandedCompletionIndexCreation.HasValue) + options = options with { ForceExpandedCompletionIndexCreation = ForceExpandedCompletionIndexCreation.Value }; if (HideAdvancedMembers.HasValue) options = options with { HideAdvancedMembers = HideAdvancedMembers.Value }; @@ -133,15 +129,13 @@ private protected abstract Task BaseVerifyWorkerAsync( string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, List matchingFilters, CompletionItemFlags? flags); - internal async Task GetCompletionListAsync( + internal Task GetCompletionListAsync( CompletionService service, Document document, int position, RoslynCompletion.CompletionTrigger triggerInfo, CompletionOptions? options = null) - { - return (await service.GetCompletionsInternalAsync(document, position, options ?? GetCompletionOptions(), triggerInfo, GetRoles(document)).ConfigureAwait(false)).completionList; - } + => service.GetCompletionsAsync(document, position, options ?? GetCompletionOptions(), OptionValueSet.Empty, triggerInfo, GetRoles(document)); private protected async Task CheckResultsAsync( Document document, int position, string expectedItemOrNull, @@ -165,7 +159,7 @@ private protected async Task CheckResultsAsync( var displayOptions = SymbolDescriptionOptions.From(document.Project); var completionService = GetCompletionService(document.Project); var completionList = await GetCompletionListAsync(completionService, document, position, trigger, options); - var items = completionList == null ? ImmutableArray.Empty : completionList.Items; + var items = completionList.Items; if (hasSuggestionModeItem != null) { @@ -490,7 +484,7 @@ private async Task VerifyCustomCommitWorkerAsync( MarkupTestFile.GetPosition(expectedCodeAfterCommit, out var actualExpectedCode, out int expectedCaretPosition); - var options = CompletionOptions.From(document.Project); + var options = GetCompletionOptions(); if (commitChar.HasValue && !CommitManager.IsCommitCharacter(service.GetRules(options), completionItem, commitChar.Value)) @@ -532,7 +526,7 @@ private void VerifyCustomCommitWorker( MarkupTestFile.GetPosition(expectedCodeAfterCommit, out var actualExpectedCode, out int expectedCaretPosition); var workspace = workspaceFixture.Target.GetWorkspace(); - var options = CompletionOptions.From(workspace.CurrentSolution.Options, service.Language); + var options = GetCompletionOptions(); if (commitChar.HasValue && !CommitManager.IsCommitCharacter(service.GetRules(options), completionItem, commitChar.Value)) @@ -587,12 +581,13 @@ private async Task VerifyProviderCommitCheckResultsAsync( var service = GetCompletionService(document.Project); var completionList = await GetCompletionListAsync(service, document, position, RoslynCompletion.CompletionTrigger.Invoke); var items = completionList.Items; + Assert.Contains(items, i => i.DisplayText + i.DisplayTextSuffix == itemToCommit); var firstItem = items.First(i => CompareItems(i.DisplayText + i.DisplayTextSuffix, itemToCommit)); var commitChar = commitCharOpt ?? '\t'; var text = await document.GetTextAsync(); - var options = CompletionOptions.From(document.Project); + var options = GetCompletionOptions(); if (commitChar == '\t' || CommitManager.IsCommitCharacter(service.GetRules(options), firstItem, commitChar)) @@ -778,15 +773,20 @@ private Task VerifyItemInSameProjectAsync(string markup, string referencedCode, return VerifyItemWithReferenceWorkerAsync(xmlString, expectedItem, expectedSymbols); } - protected static string CreateMarkupForSingleProject(string markup, string referencedCode, string sourceLanguage) + protected static string CreateMarkupForSingleProject( + string sourceCode, + string referencedCode, + string sourceLanguage, + string sourceFileName = "SourceDocument", + string referencedFileName = "ReferencedDocument") { return string.Format(@" - - {1} - {2} + + {1} + {2} -", sourceLanguage, SecurityElement.Escape(markup), SecurityElement.Escape(referencedCode)); +", sourceLanguage, SecurityElement.Escape(sourceCode), SecurityElement.Escape(referencedCode), sourceFileName, referencedFileName); } private async Task VerifyItemWithReferenceWorkerAsync( @@ -1042,7 +1042,7 @@ private void VerifyTextualTriggerCharacterWorker( TriggerInArgumentLists = showCompletionInArgumentLists }; - var isTextualTriggerCharacterResult = service.ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, text, position + 1, trigger, options, GetRoles(document)); + var isTextualTriggerCharacterResult = service.ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, text, position + 1, trigger, options, document.Project.Solution.Options, GetRoles(document)); if (expectedTriggerCharacter) { @@ -1072,7 +1072,7 @@ protected async Task VerifyCommonCommitCharactersAsync(string initialMarkup, str protected async Task VerifyCommitCharactersAsync(string initialMarkup, string textTypedSoFar, char[] validChars, char[] invalidChars = null, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular) { Assert.NotNull(validChars); - invalidChars = invalidChars ?? new[] { 'x' }; + invalidChars ??= new[] { 'x' }; using (var workspace = CreateWorkspace(initialMarkup)) { @@ -1082,7 +1082,7 @@ protected async Task VerifyCommitCharactersAsync(string initialMarkup, string te var documentId = workspace.GetDocumentId(hostDocument); var document = workspace.CurrentSolution.GetDocument(documentId); var position = hostDocument.CursorPosition.Value; - var options = CompletionOptions.From(document.Project); + var options = GetCompletionOptions(); var service = GetCompletionService(document.Project); var completionList = await GetCompletionListAsync(service, document, position, RoslynCompletion.CompletionTrigger.Invoke); @@ -1119,7 +1119,7 @@ protected async Task VerifyCommitCharactersAsync(string initialMarkup, string te var completionService = GetCompletionService(document.Project); var completionList = await GetCompletionListAsync(completionService, document, position, trigger); - return completionList == null ? ImmutableArray.Empty : completionList.Items; + return completionList.Items; } } } diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs index bd97c0ed0d506..dd582b79c9eff 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Editor.InlineDiagnostics; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.VisualStudio.Text.Tagging; @@ -45,6 +46,14 @@ public DiagnosticTaggerWrapper( var analyzerReference = new TestAnalyzerReferenceByLanguage(analyzerMap ?? DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()); workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + // Change the background analysis scope to OpenFiles instead of ActiveFile (default), + // so that every diagnostic tagger test does not need to mark test files as "active" file. + var csKey = new OptionKey2(SolutionCrawlerOptions.BackgroundAnalysisScopeOption, LanguageNames.CSharp); + var vbKey = new OptionKey2(SolutionCrawlerOptions.BackgroundAnalysisScopeOption, LanguageNames.VisualBasic); + workspace.SetOptions(workspace.Options + .WithChangedOption(csKey, BackgroundAnalysisScope.OpenFiles) + .WithChangedOption(vbKey, BackgroundAnalysisScope.OpenFiles)); + _workspace = workspace; _registrationService = (SolutionCrawlerRegistrationService)workspace.Services.GetRequiredService(); diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs index f8ff7ad4052c4..7a1351252102d 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/EditAndContinueTestHelpers.cs @@ -221,7 +221,16 @@ public static void VerifyDiagnostics(IEnumerable => VerifyDiagnostics(expected, actual.ToDescription(newSource, expected.Any(d => d.FirstLine != null))); public static void VerifyDiagnostics(IEnumerable expected, IEnumerable actual, string? message = null) - => AssertEx.SetEqual(expected, actual, message: message, itemSeparator: ",\r\n"); + { + // Assert that the diagnostics are actually what the test expects + AssertEx.SetEqual(expected, actual, message: message, itemSeparator: ",\r\n"); + + // Also make sure to realise each diagnostic to ensure its message is able to be formatted + foreach (var diagnostic in actual) + { + diagnostic.VerifyMessageFormat(); + } + } private void VerifySemanticEdits( ImmutableArray expectedSemanticEdits, diff --git a/src/EditorFeatures/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs b/src/EditorFeatures/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs index 56f098cc95011..7837cdfc71e93 100644 --- a/src/EditorFeatures/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs +++ b/src/EditorFeatures/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs @@ -6,8 +6,8 @@ using System; using System.Linq; -using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; +using Xunit; namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests { @@ -56,5 +56,19 @@ public override string ToString() return $"Diagnostic(RudeEditKind.{_rudeEditKind}, {arguments}){withLine}"; } + + internal void VerifyMessageFormat() + { + var descriptior = EditAndContinueDiagnosticDescriptors.GetDescriptor(_rudeEditKind); + var format = descriptior.MessageFormat.ToString(); + try + { + string.Format(format, _arguments); + } + catch (FormatException) + { + Assert.True(false, $"Message format string was not supplied enough arguments.\nRudeEditKind: {_rudeEditKind}\nArguments supplied: {_arguments.Length}\nFormat string: {format}"); + } + } } } diff --git a/src/EditorFeatures/TestUtilities/EmbeddedLanguages/EmbeddedLanguagesTestConstants.cs b/src/EditorFeatures/TestUtilities/EmbeddedLanguages/EmbeddedLanguagesTestConstants.cs new file mode 100644 index 0000000000000..51cf3e2303d64 --- /dev/null +++ b/src/EditorFeatures/TestUtilities/EmbeddedLanguages/EmbeddedLanguagesTestConstants.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.Security; + +namespace Microsoft.CodeAnalysis.Test.Utilities.EmbeddedLanguages +{ + internal static class EmbeddedLanguagesTestConstants + { + public static readonly string StringSyntaxAttributeCodeCSharp = @" +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + public sealed class StringSyntaxAttribute : Attribute + { + public StringSyntaxAttribute(string syntax) + { + Syntax = syntax; + Arguments = Array.Empty(); + } + + public StringSyntaxAttribute(string syntax, params object?[] arguments) + { + Syntax = syntax; + Arguments = arguments; + } + + public string Syntax { get; } + public object?[] Arguments { get; } + + public const string DateTimeFormat = nameof(DateTimeFormat); + public const string Json = nameof(Json); + public const string Regex = nameof(Regex); + } +}"; + + public static readonly string StringSyntaxAttributeCodeVB = @" +Namespace System.Diagnostics.CodeAnalysis + + Public NotInheritable Class StringSyntaxAttribute + Inherits Attribute + + Public Sub New(syntax As String) + Me.Syntax = syntax + Arguments = Array.Empty(Of Object)() + End Sub + + Public Sub New(syntax As String, ParamArray arguments As Object()) + Me.Syntax = syntax + Me.Arguments = arguments + End Sub + + Public ReadOnly Property Syntax As String + Public ReadOnly Property Arguments As Object() + + Public Const DateTimeFormat As String = NameOf(DateTimeFormat) + Public Const Json As String = NameOf(Json) + Public Const Regex As String = NameOf(Regex) + End Class +End Namespace +"; + + public static readonly string StringSyntaxAttributeCodeCSharpXml = SecurityElement.Escape(StringSyntaxAttributeCodeCSharp); + public static readonly string StringSyntaxAttributeCodeVBXml = SecurityElement.Escape(StringSyntaxAttributeCodeVB); + } +} diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs index 22f4c525fae87..e0f799d2b1bc1 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Composition; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; @@ -44,7 +45,8 @@ public Task GetExtractInterfaceOptionsAsync( List conflictingTypeNames, string defaultNamespace, string generatedNameTypeParameterSuffix, - string languageName) + string languageName, + CancellationToken cancellationToken) { this.AllExtractableMembers = extractableMembers; this.DefaultInterfaceName = defaultInterfaceName; diff --git a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs index dc38f4d5bff3c..c51a70e87b39a 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs @@ -40,6 +40,14 @@ internal Task TestAsync(string testCode, string expected, (Option2, T)[]? parseOptions); } + internal Task TestAsync(string testCode, string expected, (OptionKey, object)[]? options = null, ParseOptions? parseOptions = null) + { + return TestCoreAsync(testCode, + expected, + options, + parseOptions); + } + private async Task TestCoreAsync(string testCode, string expected, (OptionKey, T)[]? options, ParseOptions? parseOptions) { using (var workspace = CreateTestWorkspace(testCode, parseOptions)) @@ -60,9 +68,6 @@ private async Task TestCoreAsync(string testCode, string expected, (OptionKey var formattingService = document.GetRequiredLanguageService(); var formattedDocument = await formattingService.FormatNewDocumentAsync(document, hintDocument: null, CancellationToken.None); - // Format to match what AbstractEditorFactory does - formattedDocument = await Formatter.FormatAsync(formattedDocument); - var actual = await formattedDocument.GetTextAsync(); AssertEx.EqualOrDiff(expected, actual.ToString()); } diff --git a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs index 1437707b5a6b4..b905addc182d9 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Implementation.Formatting; using Microsoft.CodeAnalysis.Editor.Implementation.SmartIndent; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; @@ -140,27 +141,6 @@ private TestWorkspace CreateWorkspace(string codeWithMarker) ? TestWorkspace.CreateCSharp(codeWithMarker, composition: s_composition) : TestWorkspace.CreateVisualBasic(codeWithMarker, composition: s_composition); - internal void AssertFormatWithTransformation(Workspace workspace, string expected, OptionSet optionSet, IEnumerable rules, SyntaxNode root) - { - var newRootNode = Formatter.Format(root, SpecializedCollections.SingletonEnumerable(root.FullSpan), workspace, optionSet, rules, CancellationToken.None); - - Assert.Equal(expected, newRootNode.ToFullString()); - - // test doesn't use parsing option. add one if needed later - var newRootNodeFromString = ParseCompilationUnit(expected); - - // simple check to see whether two nodes are equivalent each other. - Assert.True(newRootNodeFromString.IsEquivalentTo(newRootNode)); - } - - internal static void AssertFormat(Workspace workspace, string expected, OptionSet optionSet, IEnumerable rules, ITextBuffer clonedBuffer, SyntaxNode root) - { - var changes = Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(root.FullSpan), workspace, optionSet, rules, CancellationToken.None); - var actual = ApplyResultAndGetFormattedText(clonedBuffer, changes); - - Assert.Equal(expected, actual); - } - private static string ApplyResultAndGetFormattedText(ITextBuffer buffer, IList changes) { using (var edit = buffer.CreateEdit()) @@ -199,26 +179,29 @@ protected async Task AssertFormatAsync(string expected, string code, IEnumerable factory.TextSpan = spans.First(); } - var options = workspace.Options; + var optionSet = workspace.Options; if (changedOptionSet != null) { foreach (var entry in changedOptionSet) { - options = options.WithChangedOption(entry.Key, entry.Value); + optionSet = optionSet.WithChangedOption(entry.Key, entry.Value); } } var root = await syntaxTree.GetRootAsync(); - var rules = formattingRuleProvider.CreateRule(workspace.CurrentSolution.GetDocument(syntaxTree), 0).Concat(Formatter.GetDefaultFormattingRules(workspace, root.Language)); + var options = SyntaxFormattingOptions.Create(optionSet, workspace.Services, root.Language); + + document = workspace.CurrentSolution.GetDocument(syntaxTree); + var rules = formattingRuleProvider.CreateRule(document, 0).Concat(Formatter.GetDefaultFormattingRules(document)); AssertFormat(workspace, expected, options, rules, clonedBuffer, root, spans); // format with node and transform AssertFormatWithTransformation(workspace, expected, options, rules, root, spans); } - internal void AssertFormatWithTransformation(Workspace workspace, string expected, OptionSet optionSet, IEnumerable rules, SyntaxNode root, IEnumerable spans) + internal void AssertFormatWithTransformation(Workspace workspace, string expected, SyntaxFormattingOptions options, IEnumerable rules, SyntaxNode root, IEnumerable spans) { - var newRootNode = Formatter.Format(root, spans, workspace, optionSet, rules, CancellationToken.None); + var newRootNode = Formatter.Format(root, spans, workspace.Services, options, rules, CancellationToken.None); Assert.Equal(expected, newRootNode.ToFullString()); @@ -229,9 +212,9 @@ internal void AssertFormatWithTransformation(Workspace workspace, string expecte Assert.True(newRootNodeFromString.IsEquivalentTo(newRootNode)); } - internal void AssertFormat(Workspace workspace, string expected, OptionSet optionSet, IEnumerable rules, ITextBuffer clonedBuffer, SyntaxNode root, IEnumerable spans) + internal void AssertFormat(Workspace workspace, string expected, SyntaxFormattingOptions options, IEnumerable rules, ITextBuffer clonedBuffer, SyntaxNode root, IEnumerable spans) { - var result = Formatter.GetFormattedTextChanges(root, spans, workspace, optionSet, rules, CancellationToken.None); + var result = Formatter.GetFormattedTextChanges(root, spans, workspace.Services, options, rules, CancellationToken.None); var actual = ApplyResultAndGetFormattedText(clonedBuffer, result); if (actual != expected) @@ -298,7 +281,10 @@ await AssertFormatAsync( /// uses an for formatting context, since the is not associated with a protected static void AssertFormatOnArbitraryNode(SyntaxNode node, string expected) { - var result = Formatter.Format(node, new AdhocWorkspace()); + using var workspace = new AdhocWorkspace(); + var formattingService = workspace.Services.GetLanguageServices(node.Language).GetRequiredService(); + var options = formattingService.GetFormattingOptions(DictionaryAnalyzerConfigOptions.Empty); + var result = Formatter.Format(node, workspace.Services, options, CancellationToken.None); var actual = result.GetText().ToString(); Assert.Equal(expected, actual); diff --git a/src/EditorFeatures/TestUtilities/KeywordHighlighting/AbstractKeywordHighlighterTests.cs b/src/EditorFeatures/TestUtilities/KeywordHighlighting/AbstractKeywordHighlighterTests.cs index e74b3a3f0b78a..a813d698e7edc 100644 --- a/src/EditorFeatures/TestUtilities/KeywordHighlighting/AbstractKeywordHighlighterTests.cs +++ b/src/EditorFeatures/TestUtilities/KeywordHighlighting/AbstractKeywordHighlighterTests.cs @@ -9,8 +9,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Xunit; diff --git a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs b/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs index 261b85d0d82b1..bacaddd1f8a5d 100644 --- a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs +++ b/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs @@ -284,7 +284,7 @@ protected Task CreateVisualBasicTestLspServerAsync(string markup) => CreateTestLspServerAsync(new string[] { markup }, LanguageNames.VisualBasic); protected Task CreateMultiProjectLspServerAsync(string xmlMarkup) - => CreateTestLspServerAsync(TestWorkspace.Create(xmlMarkup, composition: Composition)); + => CreateTestLspServerAsync(TestWorkspace.Create(xmlMarkup, composition: Composition), WellKnownLspServerKinds.AlwaysActiveVSLspServer); /// /// Creates an LSP server backed by a workspace instance with a solution containing the specified documents. @@ -292,7 +292,10 @@ protected Task CreateMultiProjectLspServerAsync(string xmlMarkup) protected Task CreateTestLspServerAsync(string[] markups) => CreateTestLspServerAsync(markups, LanguageNames.CSharp); - private Task CreateTestLspServerAsync(string[] markups, string languageName) + private protected Task CreateTestLspServerAsync(string markup, WellKnownLspServerKinds serverKind) + => CreateTestLspServerAsync(new string[] { markup }, LanguageNames.CSharp, serverKind); + + private Task CreateTestLspServerAsync(string[] markups, string languageName, WellKnownLspServerKinds serverKind = WellKnownLspServerKinds.AlwaysActiveVSLspServer) { var workspace = languageName switch { @@ -301,10 +304,10 @@ private Task CreateTestLspServerAsync(string[] markups, string la _ => throw new ArgumentException($"language name {languageName} is not valid for a test workspace"), }; - return CreateTestLspServerAsync(workspace); + return CreateTestLspServerAsync(workspace, serverKind); } - private static async Task CreateTestLspServerAsync(TestWorkspace workspace) + private static async Task CreateTestLspServerAsync(TestWorkspace workspace, WellKnownLspServerKinds serverKind) { var solution = workspace.CurrentSolution; @@ -320,7 +323,7 @@ private static async Task CreateTestLspServerAsync(TestWorkspace // created by the initial test steps. This can interfere with the expected test state. await WaitForWorkspaceOperationsAsync(workspace); - return new TestLspServer(workspace); + return new TestLspServer(workspace, serverKind); } protected async Task CreateXmlTestLspServerAsync(string xmlContent, string? workspaceKind = null) @@ -393,18 +396,18 @@ static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText } } - private static RequestDispatcher CreateRequestDispatcher(TestWorkspace workspace) + private static RequestDispatcher CreateRequestDispatcher(TestWorkspace workspace, WellKnownLspServerKinds serverKind) { var factory = workspace.ExportProvider.GetExportedValue(); - return factory.CreateRequestDispatcher(ProtocolConstants.RoslynLspLanguages); + return factory.CreateRequestDispatcher(ProtocolConstants.RoslynLspLanguages, serverKind); } - private static RequestExecutionQueue CreateRequestQueue(TestWorkspace workspace) + private static RequestExecutionQueue CreateRequestQueue(TestWorkspace workspace, WellKnownLspServerKinds serverKind) { var registrationService = workspace.GetService(); var globalOptions = workspace.GetService(); var lspMiscFilesWorkspace = new LspMiscellaneousFilesWorkspace(NoOpLspLogger.Instance); - return new RequestExecutionQueue(NoOpLspLogger.Instance, registrationService, lspMiscFilesWorkspace, globalOptions, ProtocolConstants.RoslynLspLanguages, serverName: "Tests", "TestClient"); + return new RequestExecutionQueue(NoOpLspLogger.Instance, registrationService, lspMiscFilesWorkspace, globalOptions, ProtocolConstants.RoslynLspLanguages, serverKind); } private static string GetDocumentFilePathFromName(string documentName) @@ -456,12 +459,12 @@ public sealed class TestLspServer : IDisposable private readonly RequestExecutionQueue _executionQueue; private readonly Dictionary> _locations; - internal TestLspServer(TestWorkspace testWorkspace) + internal TestLspServer(TestWorkspace testWorkspace, WellKnownLspServerKinds serverKind = WellKnownLspServerKinds.AlwaysActiveVSLspServer) { TestWorkspace = testWorkspace; _locations = GetAnnotatedLocations(testWorkspace, testWorkspace.CurrentSolution); - _requestDispatcher = CreateRequestDispatcher(testWorkspace); - _executionQueue = CreateRequestQueue(testWorkspace); + _requestDispatcher = CreateRequestDispatcher(testWorkspace, serverKind); + _executionQueue = CreateRequestQueue(testWorkspace, serverKind); var workspaceWaiter = GetWorkspaceWaiter(testWorkspace); Assert.False(workspaceWaiter.HasPendingWork); diff --git a/src/EditorFeatures/TestUtilities/RefactoringHelpers/RefactoringHelpersTestBase.cs b/src/EditorFeatures/TestUtilities/RefactoringHelpers/RefactoringHelpersTestBase.cs index a4da85d5e80a7..773257df73479 100644 --- a/src/EditorFeatures/TestUtilities/RefactoringHelpers/RefactoringHelpersTestBase.cs +++ b/src/EditorFeatures/TestUtilities/RefactoringHelpers/RefactoringHelpersTestBase.cs @@ -29,12 +29,13 @@ public abstract class RefactoringHelpersTestBase : TestBase private protected ReferenceCountedDisposable GetOrCreateWorkspaceFixture() => _fixtureHelper.GetOrCreateFixture(); - protected Task TestAsync(string text) where TNode : SyntaxNode => TestAsync(text, Functions.True); + protected Task TestAsync(string text, bool allowEmptyNodes = false) where TNode : SyntaxNode + => TestAsync(text, Functions.True, allowEmptyNodes); - protected async Task TestAsync(string text, Func predicate) where TNode : SyntaxNode + protected async Task TestAsync(string text, Func predicate, bool allowEmptyNodes = false) where TNode : SyntaxNode { text = GetSelectionAndResultSpans(text, out var selection, out var result); - var resultNode = await GetNodeForSelectionAsync(text, selection, predicate).ConfigureAwait(false); + var resultNode = await GetNodeForSelectionAsync(text, selection, predicate, allowEmptyNodes).ConfigureAwait(false); Assert.NotNull(resultNode); Assert.Equal(result, resultNode.Span); @@ -58,12 +59,14 @@ protected async Task TestNotUnderselectedAsync(string text) where TNode : Assert.False(CodeRefactoringHelpers.IsNodeUnderselected(resultNode, selection)); } - protected Task TestMissingAsync(string text) where TNode : SyntaxNode => TestMissingAsync(text, Functions.True); - protected async Task TestMissingAsync(string text, Func predicate) where TNode : SyntaxNode + protected Task TestMissingAsync(string text, bool allowEmptyNodes = false) where TNode : SyntaxNode + => TestMissingAsync(text, Functions.True, allowEmptyNodes); + + protected async Task TestMissingAsync(string text, Func predicate, bool allowEmptyNodes = false) where TNode : SyntaxNode { text = GetSelectionSpan(text, out var selection); - var resultNode = await GetNodeForSelectionAsync(text, selection, predicate).ConfigureAwait(false); + var resultNode = await GetNodeForSelectionAsync(text, selection, predicate, allowEmptyNodes).ConfigureAwait(false); Assert.Null(resultNode); } @@ -98,12 +101,12 @@ private static string GetSelectionAndResultSpans(string text, out TextSpan selec return text; } - private async Task GetNodeForSelectionAsync(string text, TextSpan selection, Func predicate) where TNode : SyntaxNode + private async Task GetNodeForSelectionAsync(string text, TextSpan selection, Func predicate, bool allowEmptyNodes = false) where TNode : SyntaxNode { using var workspaceFixture = GetOrCreateWorkspaceFixture(); var document = workspaceFixture.Target.UpdateDocument(text, SourceCodeKind.Regular); - var relevantNodes = await document.GetRelevantNodesAsync(selection, CancellationToken.None).ConfigureAwait(false); + var relevantNodes = await document.GetRelevantNodesAsync(selection, allowEmptyNodes, CancellationToken.None).ConfigureAwait(false); return relevantNodes.FirstOrDefault(predicate); } diff --git a/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs b/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs index 95a8fd566269e..18e982dec9f9c 100644 --- a/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs +++ b/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; @@ -65,10 +66,12 @@ protected async Task TestRenameDocument( documentIdToDocumentInfoMap.Add((documentId, endDocuments[i])); } + var options = new DocumentRenameOptions(); + foreach (var (documentId, endDocument) in documentIdToDocumentInfoMap) { var document = solution.GetDocument(documentId); - var documentRenameResult = await Rename.Renamer.RenameDocumentAsync(document, endDocument.DocumentName, endDocument.DocumentFolders); + var documentRenameResult = await Rename.Renamer.RenameDocumentAsync(document, options, endDocument.DocumentName, endDocument.DocumentFolders); foreach (var action in documentRenameResult.ApplicableActions) { @@ -196,10 +199,12 @@ protected async Task TestEmptyActionSet(string startText, string newDocumentName documentIdToDocumentInfoMap.Add((documentId, endDocuments[i])); } + var options = new DocumentRenameOptions(); + foreach (var (documentId, endDocument) in documentIdToDocumentInfoMap) { var document = solution.GetDocument(documentId); - var documentRenameResult = await Rename.Renamer.RenameDocumentAsync(document, endDocument.DocumentName, endDocument.DocumentFolders); + var documentRenameResult = await Rename.Renamer.RenameDocumentAsync(document, options, endDocument.DocumentName, endDocument.DocumentFolders); Assert.Empty(documentRenameResult.ApplicableActions); } } @@ -230,8 +235,9 @@ protected async Task TestRenameMappedFile(string startText, string documentName, solution = solution.AddDocument(documentInfo); + var options = new DocumentRenameOptions(); var document = solution.GetDocument(documentId); - var documentRenameResult = await Rename.Renamer.RenameDocumentAsync(document, newDocumentName, GetDocumentFolders(s_defaultDocumentPath)); + var documentRenameResult = await Rename.Renamer.RenameDocumentAsync(document, options, newDocumentName, GetDocumentFolders(s_defaultDocumentPath)); Assert.Empty(documentRenameResult.ApplicableActions); } } diff --git a/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs b/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs index 18c1bc6fde0d5..e3c3a7189071c 100644 --- a/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs @@ -185,7 +185,7 @@ private async Task VerifyCurrentParameterNameWorkerAsync(string markup, string e private static void CompareAndAssertCollectionsAndCurrentParameter( IEnumerable expectedTestItems, SignatureHelpItems actualSignatureHelpItems) { - Assert.Equal(expectedTestItems.Count(), actualSignatureHelpItems.Items.Count()); + Assert.True(expectedTestItems.Count() == actualSignatureHelpItems.Items.Count(), $"Expected {expectedTestItems.Count()} items, but got {actualSignatureHelpItems.Items.Count()}"); for (var i = 0; i < expectedTestItems.Count(); i++) { @@ -240,7 +240,7 @@ private static void CompareSigHelpItemsAndCurrentPosition( if (expectedTestItem.CurrentParameterIndex != null) { - Assert.Equal(expectedTestItem.CurrentParameterIndex, items.ArgumentIndex); + Assert.True(expectedTestItem.CurrentParameterIndex == items.ArgumentIndex, $"The current parameter is {items.ArgumentIndex}, but we expected {expectedTestItem.CurrentParameterIndex}"); } if (expectedTestItem.Description != null) diff --git a/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs b/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs index bcf78b9d02685..5b5ad49eba120 100644 --- a/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs +++ b/src/EditorFeatures/TestUtilities/Squiggles/TestDiagnosticTagProducer.cs @@ -59,7 +59,6 @@ internal static DiagnosticData CreateDiagnosticData(TestHostDocument document, T id: "test", category: "test", message: "test", - enuMessageForBingSearch: "test", severity: DiagnosticSeverity.Error, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true, diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace.cs index e72ae63318d1e..a27daf29ab076 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace.cs @@ -45,6 +45,7 @@ public partial class TestWorkspace : Workspace public IList AdditionalDocuments { get; } public IList AnalyzerConfigDocuments { get; } public IList ProjectionDocuments { get; } + internal IGlobalOptionService GlobalOptions { get; } internal override bool IgnoreUnchangeableDocumentsWhenApplyingChanges { get; } @@ -79,6 +80,7 @@ public TestWorkspace( this.CanApplyChangeDocument = true; this.IgnoreUnchangeableDocumentsWhenApplyingChanges = ignoreUnchangeableDocumentsWhenApplyingChanges; + this.GlobalOptions = GetService(); if (Services.GetService() is INotificationServiceCallback callback) { diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_Create.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_Create.cs index 5da952c24d78a..3602ea8926fb1 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_Create.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_Create.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.ServiceModel.Configuration; using System.Xml.Linq; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Test.Utilities; @@ -50,6 +51,7 @@ public partial class TestWorkspace private const string CommonReferencesNet45AttributeName = "CommonReferencesNet45"; private const string CommonReferencesPortableAttributeName = "CommonReferencesPortable"; private const string CommonReferencesNetCoreAppName = "CommonReferencesNetCoreApp"; + private const string CommonReferencesNet6Name = "CommonReferencesNet6"; private const string CommonReferencesNetStandard20Name = "CommonReferencesNetStandard20"; private const string ReferencesOnDiskAttributeName = "ReferencesOnDisk"; private const string FilePathAttributeName = "FilePath"; @@ -62,6 +64,7 @@ public partial class TestWorkspace private const string LinkAssemblyNameAttributeName = "LinkAssemblyName"; private const string LinkProjectNameAttributeName = "LinkProjectName"; private const string LinkFilePathAttributeName = "LinkFilePath"; + private const string MarkupAttributeName = "Markup"; private const string PreprocessorSymbolsAttributeName = "PreprocessorSymbols"; private const string AnalyzerDisplayAttributeName = "Name"; private const string AnalyzerFullPathAttributeName = "FullPath"; @@ -136,10 +139,11 @@ internal static TestWorkspace Create( string workspaceKind = null, string extension = null, bool commonReferences = true, + bool isMarkup = true, bool openDocuments = false, IDocumentServiceProvider documentServiceProvider = null) { - var workspaceElement = CreateWorkspaceElement(language, compilationOptions, parseOptions, files, sourceGeneratedFiles, metadataReferences, extension, commonReferences); + var workspaceElement = CreateWorkspaceElement(language, compilationOptions, parseOptions, files, sourceGeneratedFiles, metadataReferences, extension, commonReferences, isMarkup); return Create(workspaceElement, openDocuments, exportProvider, composition, workspaceKind, documentServiceProvider); } @@ -193,9 +197,10 @@ public static TestWorkspace CreateCSharp( ExportProvider exportProvider = null, TestComposition composition = null, string[] metadataReferences = null, + bool isMarkup = true, bool openDocuments = false) { - return CreateCSharp(new[] { file }, Array.Empty(), parseOptions, compilationOptions, exportProvider, composition, metadataReferences, openDocuments); + return CreateCSharp(new[] { file }, Array.Empty(), parseOptions, compilationOptions, exportProvider, composition, metadataReferences, isMarkup, openDocuments); } public static TestWorkspace CreateCSharp( @@ -206,9 +211,10 @@ public static TestWorkspace CreateCSharp( ExportProvider exportProvider = null, TestComposition composition = null, string[] metadataReferences = null, + bool isMarkup = true, bool openDocuments = false) { - return Create(LanguageNames.CSharp, compilationOptions, parseOptions, files, sourceGeneratedFiles, exportProvider, composition, metadataReferences, openDocuments: openDocuments); + return Create(LanguageNames.CSharp, compilationOptions, parseOptions, files, sourceGeneratedFiles, exportProvider, composition, metadataReferences, isMarkup: isMarkup, openDocuments: openDocuments); } public static TestWorkspace CreateCSharp2( diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs index bd2b15e80b91e..b71ea15af254d 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs @@ -787,8 +787,23 @@ private static TestHostDocument CreateDocument( : (SourceCodeKind)Enum.Parse(typeof(SourceCodeKind), attr.Value); } - TestFileMarkupParser.GetPositionAndSpans(markupCode, - out var code, out int? cursorPosition, out ImmutableDictionary> spans); + var markupAttribute = documentElement.Attribute(MarkupAttributeName); + var isMarkup = markupAttribute == null || (bool)markupAttribute == true; + + string code; + int? cursorPosition; + ImmutableDictionary> spans; + + if (isMarkup) + { + TestFileMarkupParser.GetPositionAndSpans(markupCode, out code, out cursorPosition, out spans); + } + else + { + code = markupCode; + cursorPosition = null; + spans = ImmutableDictionary>.Empty; + } var testDocumentServiceProvider = GetDocumentServiceProvider(documentElement); @@ -1007,7 +1022,7 @@ private static IList CreateCommonReferences(TestWorkspace wor ((bool?)net45).HasValue && ((bool?)net45).Value) { - references = new List { TestBase.MscorlibRef_v4_0_30316_17626, TestBase.SystemRef_v4_0_30319_17929, TestBase.SystemCoreRef_v4_0_30319_17929 }; + references = new List { TestBase.MscorlibRef_v4_0_30316_17626, TestBase.SystemRef_v4_0_30319_17929, TestBase.SystemCoreRef_v4_0_30319_17929, TestBase.SystemRuntimeSerializationRef_v4_0_30319_17929 }; if (GetLanguage(workspace, element) == LanguageNames.VisualBasic) { references.Add(TestBase.MsvbRef); @@ -1078,6 +1093,14 @@ private static IList CreateCommonReferences(TestWorkspace wor references = TargetFrameworkUtil.NetStandard20References.ToList(); } + var net6 = element.Attribute(CommonReferencesNet6Name); + if (net6 != null && + ((bool?)net6).HasValue && + ((bool?)net6).Value) + { + references = TargetFrameworkUtil.GetReferences(TargetFramework.Net60).ToList(); + } + return references; } diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlCreation.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlCreation.cs index 6a10834bdce79..cacac723e7632 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlCreation.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlCreation.cs @@ -23,7 +23,8 @@ internal static XElement CreateWorkspaceElement( string[] sourceGeneratedFiles = null, string[] metadataReferences = null, string extension = null, - bool commonReferences = true) + bool commonReferences = true, + bool isMarkup = true) { var documentElements = new List(); @@ -33,7 +34,8 @@ internal static XElement CreateWorkspaceElement( { foreach (var file in files) { - documentElements.Add(CreateDocumentElement(file, GetDefaultTestSourceDocumentName(index++, extension), parseOptions)); + documentElements.Add(CreateDocumentElement( + file, GetDefaultTestSourceDocumentName(index++, extension), parseOptions, isMarkup)); } } @@ -169,12 +171,18 @@ private static XElement CreateCompilationOptionsElement(CompilationOptions optio private static XElement CreateMetadataReference(string path) => new XElement(MetadataReferenceElementName, path); - protected static XElement CreateDocumentElement(string code, string filePath, ParseOptions parseOptions = null) + protected static XElement CreateDocumentElement( + string code, string filePath, ParseOptions parseOptions = null, bool isMarkup = true) { - return new XElement(DocumentElementName, + var element = new XElement(DocumentElementName, new XAttribute(FilePathAttributeName, filePath), CreateParseOptionsElement(parseOptions), code.Replace("\r\n", "\n")); + + if (!isMarkup) + element.Add(new XAttribute(MarkupAttributeName, isMarkup)); + + return element; } protected static XElement CreateDocumentFromSourceGeneratorElement(string code, string hintName, ParseOptions parseOptions = null) diff --git a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb index bb463cb5269b5..6e421c9689479 100644 --- a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb +++ b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb @@ -26,7 +26,6 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Inherits AbstractCommandHandlerTestState Private Const timeoutMs = 60000 - Private Const editorTimeoutMs = 60000 Friend Const RoslynItem = "RoslynItem" Friend ReadOnly EditorCompletionCommandHandler As ICommandHandler Friend ReadOnly CompletionPresenterProvider As ICompletionPresenterProvider @@ -62,9 +61,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Optional roles As ImmutableArray(Of String) = Nothing) MyBase.New(workspaceElement, GetComposition(excludedTypes, extraExportedTypes, includeFormatCommandHandler), workspaceKind:=workspaceKind, makeSeparateBufferForCursor, roles) - ' The current default timeout defined in the Editor may not work on slow virtual test machines. - ' Need to use a safe timeout there to follow real code paths. - MyBase.TextView.Options.GlobalOptions.SetOptionValue(DefaultOptions.ResponsiveCompletionThresholdOptionId, editorTimeoutMs) + ' Disable editor's responsive completion option to ensure a deterministic test behavior + MyBase.TextView.Options.GlobalOptions.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, False) Dim languageServices = Me.Workspace.CurrentSolution.Projects.First().LanguageServices Dim language = languageServices.Language @@ -328,6 +326,13 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Task.WaitAny(task1, task2) End Sub + Public Async Function GetCompletionSession(Optional projectionsView As ITextView = Nothing) As Task(Of IAsyncCompletionSession) + Await WaitForAsynchronousOperationsAsync() + Dim view = If(projectionsView, TextView) + + Return GetExportedValue(Of IAsyncCompletionBroker)().GetSession(view) + End Function + Public Async Function AssertCompletionSession(Optional projectionsView As ITextView = Nothing) As Task Await WaitForAsynchronousOperationsAsync() Dim view = If(projectionsView, TextView) @@ -445,7 +450,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Dim document = Me.Workspace.CurrentSolution.Projects.First().Documents.First() Dim service = CompletionService.GetService(document) Dim roslynItem = GetSelectedItem() - Dim options = CompletionOptions.From(document.Project) + Dim options = CompletionOptions.Default Dim displayOptions = SymbolDescriptionOptions.From(document.Project) Return Await service.GetDescriptionAsync(document, roslynItem, options, displayOptions) End Function diff --git a/src/EditorFeatures/TestUtilities2/Intellisense/TestStateFactory.vb b/src/EditorFeatures/TestUtilities2/Intellisense/TestStateFactory.vb index f43b32d593481..64401fb1811a7 100644 --- a/src/EditorFeatures/TestUtilities2/Intellisense/TestStateFactory.vb +++ b/src/EditorFeatures/TestUtilities2/Intellisense/TestStateFactory.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.CSharp Imports Microsoft.CodeAnalysis.Completion +Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Friend Class TestStateFactory @@ -24,8 +25,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense excludedTypes, extraExportedTypes, includeFormatCommandHandler, workspaceKind:=Nothing) - testState.Workspace.SetOptions( - testState.Workspace.Options.WithChangedOption(CompletionOptions.Metadata.TriggerInArgumentLists, LanguageNames.CSharp, showCompletionInArgumentLists)) + testState.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) Return testState End Function @@ -52,8 +53,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Dim testState = New TestState( workspaceElement, excludedTypes:=Nothing, extraExportedTypes, includeFormatCommandHandler:=False, workspaceKind) - testState.Workspace.SetOptions( - testState.Workspace.Options.WithChangedOption(CompletionOptions.Metadata.TriggerInArgumentLists, LanguageNames.CSharp, showCompletionInArgumentLists)) + testState.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) Return testState End Function diff --git a/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockDocumentNavigationService.vb b/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockDocumentNavigationService.vb index dcdf6004c617a..378db70091a26 100644 --- a/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockDocumentNavigationService.vb +++ b/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockDocumentNavigationService.vb @@ -21,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Public _triedNavigationToSpan As Boolean Public _documentId As DocumentId - Public _options As OptionSet + Public _options As NavigationOptions Public _line As Integer = -1 Public _offset As Integer = -1 Public _span As TextSpan = Nothing @@ -44,7 +44,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Return If(_canNavigateToSpan, SpecializedTasks.True, SpecializedTasks.False) End Function - Public Function TryNavigateToLineAndOffset(workspace As Workspace, documentId As DocumentId, lineNumber As Integer, offset As Integer, options As OptionSet, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToLineAndOffset + Public Function TryNavigateToLineAndOffset(workspace As Workspace, documentId As DocumentId, lineNumber As Integer, offset As Integer, options As NavigationOptions, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToLineAndOffset _triedNavigationToLineAndOffset = True _documentId = documentId _options = options @@ -54,7 +54,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Return _canNavigateToLineAndOffset End Function - Public Function TryNavigateToPosition(workspace As Workspace, documentId As DocumentId, position As Integer, virtualSpace As Integer, options As OptionSet, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToPosition + Public Function TryNavigateToPosition(workspace As Workspace, documentId As DocumentId, position As Integer, virtualSpace As Integer, options As NavigationOptions, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToPosition _triedNavigationToPosition = True _documentId = documentId _options = options @@ -64,7 +64,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Return _canNavigateToPosition End Function - Public Function TryNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As OptionSet, allowInvalidSpan As Boolean, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToSpan + Public Function TryNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As NavigationOptions, allowInvalidSpan As Boolean, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToSpan _triedNavigationToSpan = True _documentId = documentId _options = options @@ -73,7 +73,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Return _canNavigateToSpan End Function - Public Function TryNavigateToSpanAsync(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As OptionSet, allowInvalidSpan As Boolean, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IDocumentNavigationService.TryNavigateToSpanAsync + Public Function TryNavigateToSpanAsync(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As NavigationOptions, allowInvalidSpan As Boolean, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IDocumentNavigationService.TryNavigateToSpanAsync _triedNavigationToSpan = True _documentId = documentId _options = options diff --git a/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockNavigableItemsPresenter.vb b/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockNavigableItemsPresenter.vb index 7f7f85144f576..4297c81ee498e 100644 --- a/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockNavigableItemsPresenter.vb +++ b/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockNavigableItemsPresenter.vb @@ -3,19 +3,20 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.FindUsages Imports Microsoft.CodeAnalysis.Editor.Host Imports Microsoft.CodeAnalysis.FindUsages +Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Friend Class MockStreamingFindUsagesPresenter Implements IStreamingFindUsagesPresenter - Public ReadOnly Context As New SimpleFindUsagesContext() + Public ReadOnly Context As SimpleFindUsagesContext Private ReadOnly _action As Action - Public Sub New(action As Action) + Public Sub New(globalOptions As IGlobalOptionService, action As Action) _action = action + Context = New SimpleFindUsagesContext(globalOptions) End Sub Public Sub ClearAll() Implements IStreamingFindUsagesPresenter.ClearAll diff --git a/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockSymbolNavigationService.vb b/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockSymbolNavigationService.vb index 74df2f621881a..c8cae184b1aff 100644 --- a/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockSymbolNavigationService.vb +++ b/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockSymbolNavigationService.vb @@ -17,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Public _triedSymbolNavigationNotify As Boolean Public _wouldNavigateToSymbol As Boolean - Public Function TryNavigateToSymbol(symbol As ISymbol, project As Project, Optional options As OptionSet = Nothing, Optional cancellationToken As CancellationToken = Nothing) As Boolean Implements ISymbolNavigationService.TryNavigateToSymbol + Public Function TryNavigateToSymbol(symbol As ISymbol, project As Project, options As NavigationOptions, cancellationToken As CancellationToken) As Boolean Implements ISymbolNavigationService.TryNavigateToSymbol _triedNavigationToSymbol = True Return True End Function diff --git a/src/EditorFeatures/TestUtilities2/Utilities/MockDocumentNavigationServiceProvider.vb b/src/EditorFeatures/TestUtilities2/Utilities/MockDocumentNavigationServiceProvider.vb index 20600f3e6c353..4d0669dc837ae 100644 --- a/src/EditorFeatures/TestUtilities2/Utilities/MockDocumentNavigationServiceProvider.vb +++ b/src/EditorFeatures/TestUtilities2/Utilities/MockDocumentNavigationServiceProvider.vb @@ -38,7 +38,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Public ProvidedOffset As Integer Public ProvidedPosition As Integer Public ProvidedVirtualSpace As Integer - Public ProvidedOptions As OptionSet + Public ProvidedOptions As NavigationOptions Public CanNavigateToLineAndOffsetReturnValue As Boolean = True Public CanNavigateToPositionReturnValue As Boolean = True @@ -77,7 +77,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Return If(CanNavigateToSpanReturnValue, SpecializedTasks.True, SpecializedTasks.False) End Function - Public Function TryNavigateToLineAndOffset(workspace As Workspace, documentId As DocumentId, lineNumber As Integer, offset As Integer, options As OptionSet, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToLineAndOffset + Public Function TryNavigateToLineAndOffset(workspace As Workspace, documentId As DocumentId, lineNumber As Integer, offset As Integer, options As NavigationOptions, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToLineAndOffset Me.ProvidedDocumentId = documentId Me.ProvidedLineNumber = lineNumber Me.ProvidedOffset = offset @@ -86,7 +86,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Return TryNavigateToLineAndOffsetReturnValue End Function - Public Function TryNavigateToPosition(workspace As Workspace, documentId As DocumentId, position As Integer, virtualSpace As Integer, options As OptionSet, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToPosition + Public Function TryNavigateToPosition(workspace As Workspace, documentId As DocumentId, position As Integer, virtualSpace As Integer, options As NavigationOptions, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToPosition Me.ProvidedDocumentId = documentId Me.ProvidedPosition = position Me.ProvidedVirtualSpace = virtualSpace @@ -95,7 +95,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Return TryNavigateToPositionReturnValue End Function - Public Function TryNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As OptionSet, allowInvalidSpans As Boolean, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToSpan + Public Function TryNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As NavigationOptions, allowInvalidSpans As Boolean, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToSpan Me.ProvidedDocumentId = documentId Me.ProvidedTextSpan = textSpan Me.ProvidedOptions = options @@ -103,7 +103,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Return TryNavigateToSpanReturnValue End Function - Public Function TryNavigateToSpanAsync(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As OptionSet, allowInvalidSpans As Boolean, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IDocumentNavigationService.TryNavigateToSpanAsync + Public Function TryNavigateToSpanAsync(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As NavigationOptions, allowInvalidSpans As Boolean, cancellationToken As CancellationToken) As Task(Of Boolean) Implements IDocumentNavigationService.TryNavigateToSpanAsync Me.ProvidedDocumentId = documentId Me.ProvidedTextSpan = textSpan Me.ProvidedOptions = options diff --git a/src/EditorFeatures/TestUtilities2/Utilities/MockSymbolNavigationServiceProvider.vb b/src/EditorFeatures/TestUtilities2/Utilities/MockSymbolNavigationServiceProvider.vb index 3d5e889e983d3..23b7ff8cf3a24 100644 --- a/src/EditorFeatures/TestUtilities2/Utilities/MockSymbolNavigationServiceProvider.vb +++ b/src/EditorFeatures/TestUtilities2/Utilities/MockSymbolNavigationServiceProvider.vb @@ -34,7 +34,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Public TryNavigateToSymbolProvidedSymbol As ISymbol Public TryNavigateToSymbolProvidedProject As Project - Public TryNavigateToSymbolProvidedOptions As OptionSet + Public TryNavigateToSymbolProvidedOptions As NavigationOptions Public TrySymbolNavigationNotifyProvidedSymbol As ISymbol Public TrySymbolNavigationNotifyProvidedProject As Project @@ -45,7 +45,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Public NavigationLineNumberReturnValue As Integer Public NavigationCharOffsetReturnValue As Integer - Public Function TryNavigateToSymbol(symbol As ISymbol, project As Project, Optional options As OptionSet = Nothing, Optional cancellationToken As CancellationToken = Nothing) As Boolean Implements ISymbolNavigationService.TryNavigateToSymbol + Public Function TryNavigateToSymbol(symbol As ISymbol, project As Project, options As NavigationOptions, cancellationToken As CancellationToken) As Boolean Implements ISymbolNavigationService.TryNavigateToSymbol Me.TryNavigateToSymbolProvidedSymbol = symbol Me.TryNavigateToSymbolProvidedProject = project Me.TryNavigateToSymbolProvidedOptions = options diff --git a/src/EditorFeatures/VisualBasic/EmbeddedLanguages/VisualBasicEmbeddedLanguageEditorFeaturesProvider.vb b/src/EditorFeatures/VisualBasic/EmbeddedLanguages/VisualBasicEmbeddedLanguageEditorFeaturesProvider.vb index 69adb41dc540e..1a1e3bb91273d 100644 --- a/src/EditorFeatures/VisualBasic/EmbeddedLanguages/VisualBasicEmbeddedLanguageEditorFeaturesProvider.vb +++ b/src/EditorFeatures/VisualBasic/EmbeddedLanguages/VisualBasicEmbeddedLanguageEditorFeaturesProvider.vb @@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages MyBase.New(VisualBasicEmbeddedLanguagesProvider.Info) End Sub - Friend Overrides Function EscapeText(text As String, token As SyntaxToken) As String + Public Overrides Function EscapeText(text As String, token As SyntaxToken) As String Return EmbeddedLanguageUtilities.EscapeText(text) End Function End Class diff --git a/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesLSPService.vb b/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesLSPService.vb index bd1bfaf985bae..40c58220e3c46 100644 --- a/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesLSPService.vb +++ b/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesLSPService.vb @@ -3,8 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Composition -Imports Microsoft.CodeAnalysis.Editor.FindUsages -Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities +Imports Microsoft.CodeAnalysis.FindUsages Imports Microsoft.CodeAnalysis.Host.Mef Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.FindUsages diff --git a/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesService.vb b/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesService.vb index 7d82719bb8af4..87faa5bd0305d 100644 --- a/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesService.vb +++ b/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesService.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Composition -Imports Microsoft.CodeAnalysis.Editor.FindUsages +Imports Microsoft.CodeAnalysis.FindUsages Imports Microsoft.CodeAnalysis.Host.Mef Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.FindUsages diff --git a/src/EditorFeatures/VisualBasic/GoToBase/VisualBasicGoToBaseService.vb b/src/EditorFeatures/VisualBasic/GoToBase/VisualBasicGoToBaseService.vb index 68fbdc7e4b308..c69c2b91d5cbc 100644 --- a/src/EditorFeatures/VisualBasic/GoToBase/VisualBasicGoToBaseService.vb +++ b/src/EditorFeatures/VisualBasic/GoToBase/VisualBasicGoToBaseService.vb @@ -3,10 +3,10 @@ ' See the LICENSE file in the project root for more information. Imports System.Composition -Imports Microsoft.CodeAnalysis.Editor.GoToBase +Imports Microsoft.CodeAnalysis.GoToBase Imports Microsoft.CodeAnalysis.Host.Mef -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.GoToBase +Namespace Microsoft.CodeAnalysis.VisualBasic.GoToBase Friend Class VisualBasicGoToBaseService Inherits AbstractGoToBaseService diff --git a/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb b/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb index fbb111d29a3ff..b60982ca421d0 100644 --- a/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/LineCommit/CommitCommandHandler.vb @@ -7,6 +7,7 @@ Imports System.Diagnostics.CodeAnalysis Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities +Imports Microsoft.CodeAnalysis.Editor.Implementation.Formatting Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Formatting.Rules Imports Microsoft.CodeAnalysis.Options @@ -233,7 +234,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit ' Do the paste in the same transaction as the commit/format nextHandler() - If Not _globalOptions.GetOption(FormattingBehaviorOptions.FormatOnPaste, LanguageNames.VisualBasic) Then + If Not _globalOptions.GetOption(FormattingOptionsMetadata.FormatOnPaste, LanguageNames.VisualBasic) Then transaction.Complete() Return End If diff --git a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb index 8edbfac6ee5b1..66d92f0a3fde4 100644 --- a/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb +++ b/src/EditorFeatures/VisualBasic/LineCommit/CommitFormatter.vb @@ -71,9 +71,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit ' create commit formatting cleanup provider that has line commit specific behavior Dim inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService(Of IInferredIndentationService)() Dim documentOptions = inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, isExplicitFormat, cancellationToken).WaitAndGetResult(cancellationToken) + Dim formattingOptions = SyntaxFormattingOptions.Create(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language) Dim commitFormattingCleanup = GetCommitFormattingCleanupProvider( document, - documentOptions, + formattingOptions, spanToFormat, baseSnapshot, baseTree, dirtyRegion, @@ -94,7 +95,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Dim root = document.GetSyntaxRootSynchronously(cancellationToken) Dim newRoot = CodeCleaner.CleanupAsync(root, textSpanToFormat, - document.Project.Solution.Workspace, + documentOptions, + document.Project.Solution.Workspace.Services, codeCleanups, cancellationToken).WaitAndGetResult(cancellationToken) If root Is newRoot Then @@ -129,7 +131,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Private Shared Function GetCommitFormattingCleanupProvider( document As Document, - documentOptions As DocumentOptionSet, + options As SyntaxFormattingOptions, spanToFormat As SnapshotSpan, oldSnapshot As ITextSnapshot, oldTree As SyntaxTree, @@ -140,47 +142,14 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit Dim oldDirtySpan = newDirtySpan.TranslateTo(oldSnapshot, SpanTrackingMode.EdgeInclusive) ' based on changes made to dirty spans, get right formatting rules to apply - Dim rules = GetFormattingRules(document, documentOptions, spanToFormat, oldDirtySpan, oldTree, newDirtySpan, newTree, cancellationToken) + Dim rules = GetFormattingRules(document, options, spanToFormat, oldDirtySpan, oldTree, newDirtySpan, newTree, cancellationToken) - Return New SimpleCodeCleanupProvider(PredefinedCodeCleanupProviderNames.Format, - Function(doc, spans, c) FormatAsync(doc, spans, documentOptions, rules, c), - Function(r, spans, w, c) Format(r, spans, w, documentOptions, rules, c)) - End Function - - Private Shared Async Function FormatAsync(document As Document, spans As ImmutableArray(Of TextSpan), options As OptionSet, rules As IEnumerable(Of AbstractFormattingRule), cancellationToken As CancellationToken) As Task(Of Document) - ' if old text already exist, use fast path for formatting - Dim oldText As SourceText = Nothing - - If document.TryGetText(oldText) Then - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Dim newText = oldText.WithChanges(Formatter.GetFormattedTextChanges(root, spans, document.Project.Solution.Workspace, options, rules, cancellationToken)) - Return document.WithText(newText) - End If - - Return Await Formatter.FormatAsync(document, spans, options, rules, cancellationToken).ConfigureAwait(False) - End Function - - Private Shared Function Format(root As SyntaxNode, spans As ImmutableArray(Of TextSpan), workspace As Workspace, options As OptionSet, rules As IEnumerable(Of AbstractFormattingRule), cancellationToken As CancellationToken) As SyntaxNode - ' if old text already exist, use fast path for formatting - Dim oldText As SourceText = Nothing - - If root.SyntaxTree IsNot Nothing AndAlso root.SyntaxTree.TryGetText(oldText) Then - Dim changes = Formatter.GetFormattedTextChanges(root, spans, workspace, options, rules, cancellationToken) - - ' no change - If changes.Count = 0 Then - Return root - End If - - Return root.SyntaxTree.WithChangedText(oldText.WithChanges(changes)).GetRoot(cancellationToken) - End If - - Return Formatter.Format(root, spans, workspace, options, rules, cancellationToken) + Return New FormatCodeCleanupProvider(rules) End Function Private Shared Function GetFormattingRules( document As Document, - documentOptions As DocumentOptionSet, + options As SyntaxFormattingOptions, spanToFormat As SnapshotSpan, oldDirtySpan As SnapshotSpan, oldTree As SyntaxTree, @@ -232,32 +201,30 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit ' for now, do very simple checking. basically, we see whether we get same number of indent operation for the give span. alternative, but little bit ' more expensive and complex, we can actually calculate indentation right after the span, and see whether that is changed. not sure whether that much granularity ' is needed. - If GetNumberOfIndentOperations(document, documentOptions, oldTree, oldDirtySpan, cancellationToken) = - GetNumberOfIndentOperations(document, documentOptions, newTree, newDirtySpan, cancellationToken) Then + If GetNumberOfIndentOperations(document, options, oldTree, oldDirtySpan, cancellationToken) = + GetNumberOfIndentOperations(document, options, newTree, newDirtySpan, cancellationToken) Then Return (New NoAnchorFormatterRule()).Concat(Formatter.GetDefaultFormattingRules(document)) End If Return Formatter.GetDefaultFormattingRules(document) End Function - Private Shared Function GetNumberOfIndentOperations(document As Document, - documentOptions As DocumentOptionSet, - SyntaxTree As SyntaxTree, - Span As SnapshotSpan, - CancellationToken As CancellationToken) As Integer + Private Shared Function GetNumberOfIndentOperations( + document As Document, + options As SyntaxFormattingOptions, + syntaxTree As SyntaxTree, + span As SnapshotSpan, + cancellationToken As CancellationToken) As Integer ' find containing statement of the end point, and use its end point as position to get indent operation - Dim containingStatement = ContainingStatementInfo.GetInfo(Span.End, SyntaxTree, CancellationToken) - Dim endPosition = If(containingStatement Is Nothing, Span.End.Position + 1, containingStatement.TextSpan.End + 1) + Dim containingStatement = ContainingStatementInfo.GetInfo(span.End, syntaxTree, cancellationToken) + Dim endPosition = If(containingStatement Is Nothing, span.End.Position + 1, containingStatement.TextSpan.End + 1) ' get token right after given span - Dim token = SyntaxTree.GetRoot(CancellationToken).FindToken(Math.Min(endPosition, SyntaxTree.GetRoot(CancellationToken).FullSpan.End)) + Dim token = syntaxTree.GetRoot(cancellationToken).FindToken(Math.Min(endPosition, syntaxTree.GetRoot(cancellationToken).FullSpan.End)) Dim node = token.Parent - Dim optionService = document.Project.Solution.Workspace.Services.GetRequiredService(Of IOptionService)() - Dim options = documentOptions.AsAnalyzerConfigOptions(optionService, node?.Language) - ' collect all indent operation Dim operations = New List(Of IndentBlockOperation)() While node IsNot Nothing diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb index 8b1ddd6f02b20..0599324081b8b 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb @@ -50,9 +50,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Public Shared Async Function GetGeneratedDocumentAsync(document As Document, generateCodeItem As RoslynNavigationBarItem, cancellationToken As CancellationToken) As Task(Of Document) Dim syntaxTree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) Dim contextLocation = syntaxTree.GetLocation(New TextSpan(0, 0)) - Dim codeGenerationOptions As New CodeGenerationOptions(contextLocation, generateMethodBodies:=True) - Dim newDocument = Await GetGeneratedDocumentCoreAsync(document, generateCodeItem, codeGenerationOptions, cancellationToken).ConfigureAwait(False) + Dim codeGenerationContext = New CodeGenerationContext(contextLocation, generateMethodBodies:=True) + + Dim newDocument = Await GetGeneratedDocumentCoreAsync(document, generateCodeItem, codeGenerationContext, cancellationToken).ConfigureAwait(False) If newDocument Is Nothing Then Return document End If @@ -64,7 +65,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar formatterRules = LineAdjustmentFormattingRule.Instance.Concat(formatterRules) End If - Dim documentOptions = Await newDocument.GetOptionsAsync(cancellationToken).ConfigureAwait(False) + Dim documentOptions = Await document.GetOptionsAsync(cancellationToken).ConfigureAwait(False) + Return Await Formatter.FormatAsync( newDocument, Formatter.Annotation, @@ -77,26 +79,26 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Return generateCodeItem.Kind <> RoslynNavigationBarItemKind.GenerateFinalizer End Function - Private Shared Function GetGeneratedDocumentCoreAsync(document As Document, generateCodeItem As RoslynNavigationBarItem, codeGenerationOptions As CodeGenerationOptions, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Function GetGeneratedDocumentCoreAsync(document As Document, generateCodeItem As RoslynNavigationBarItem, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Select Case generateCodeItem.Kind Case RoslynNavigationBarItemKind.GenerateDefaultConstructor - Return GenerateDefaultConstructorAsync(document, DirectCast(generateCodeItem, GenerateDefaultConstructor), codeGenerationOptions, cancellationToken) + Return GenerateDefaultConstructorAsync(document, DirectCast(generateCodeItem, GenerateDefaultConstructor), codeGenerationContext, cancellationToken) Case RoslynNavigationBarItemKind.GenerateEventHandler - Return GenerateEventHandlerAsync(document, DirectCast(generateCodeItem, GenerateEventHandler), codeGenerationOptions, cancellationToken) + Return GenerateEventHandlerAsync(document, DirectCast(generateCodeItem, GenerateEventHandler), codeGenerationContext, cancellationToken) Case RoslynNavigationBarItemKind.GenerateFinalizer - Return GenerateFinalizerAsync(document, DirectCast(generateCodeItem, GenerateFinalizer), codeGenerationOptions, cancellationToken) + Return GenerateFinalizerAsync(document, DirectCast(generateCodeItem, GenerateFinalizer), codeGenerationContext, cancellationToken) Case RoslynNavigationBarItemKind.GenerateMethod - Return GenerateMethodAsync(document, DirectCast(generateCodeItem, GenerateMethod), codeGenerationOptions, cancellationToken) + Return GenerateMethodAsync(document, DirectCast(generateCodeItem, GenerateMethod), codeGenerationContext, cancellationToken) Case Else Throw ExceptionUtilities.UnexpectedValue(generateCodeItem.Kind) End Select End Function - Private Shared Async Function GenerateDefaultConstructorAsync(document As Document, generateCodeItem As GenerateDefaultConstructor, codeGenerationOptions As CodeGenerationOptions, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Async Function GenerateDefaultConstructorAsync(document As Document, generateCodeItem As GenerateDefaultConstructor, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) @@ -129,11 +131,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Return Await CodeGenerator.AddMethodDeclarationAsync(document.Project.Solution, destinationType, methodSymbol, - codeGenerationOptions, + codeGenerationContext, cancellationToken).ConfigureAwait(False) End Function - Private Shared Async Function GenerateEventHandlerAsync(document As Document, generateCodeItem As GenerateEventHandler, codeGenerationOptions As CodeGenerationOptions, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Async Function GenerateEventHandlerAsync(document As Document, generateCodeItem As GenerateEventHandler, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim eventSymbol = TryCast(generateCodeItem.EventSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).GetAnySymbol(), IEventSymbol) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).GetAnySymbol(), INamedTypeSymbol) @@ -177,11 +179,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Return Await CodeGenerator.AddMethodDeclarationAsync(document.Project.Solution, destinationType, methodSymbol, - codeGenerationOptions, + codeGenerationContext, cancellationToken).ConfigureAwait(False) End Function - Private Shared Async Function GenerateFinalizerAsync(document As Document, generateCodeItem As GenerateFinalizer, codeGenerationOptions As CodeGenerationOptions, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Async Function GenerateFinalizerAsync(document As Document, generateCodeItem As GenerateFinalizer, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) @@ -214,11 +216,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Return Await CodeGenerator.AddMethodDeclarationAsync(document.Project.Solution, destinationType, finalizerMethodSymbol, - codeGenerationOptions, + codeGenerationContext, cancellationToken).ConfigureAwait(False) End Function - Private Shared Async Function GenerateMethodAsync(document As Document, generateCodeItem As GenerateMethod, codeGenerationOptions As CodeGenerationOptions, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Async Function GenerateMethodAsync(document As Document, generateCodeItem As GenerateMethod, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) Dim methodToReplicate = TryCast(generateCodeItem.MethodToReplicateSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, IMethodSymbol) @@ -234,7 +236,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Return Await CodeGenerator.AddMethodDeclarationAsync(document.Project.Solution, destinationType, codeGenerationSymbol, - codeGenerationOptions, + codeGenerationContext, cancellationToken).ConfigureAwait(False) End Function End Class diff --git a/src/EditorFeatures/VisualBasicTest/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersTests.vb b/src/EditorFeatures/VisualBasicTest/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersTests.vb index eb9e82fc1dd7d..eb6c4b341d2a7 100644 --- a/src/EditorFeatures/VisualBasicTest/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersTests.vb +++ b/src/EditorFeatures/VisualBasicTest/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersTests.vb @@ -2,36 +2,27 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Immutable -Imports Microsoft.CodeAnalysis.AddConstructorParametersFromMembers Imports Microsoft.CodeAnalysis.CodeActions -Imports Microsoft.CodeAnalysis.CodeRefactorings -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings +Imports Microsoft.CodeAnalysis.Testing +Imports VerifyVB = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeRefactoringVerifier(Of + Microsoft.CodeAnalysis.AddConstructorParametersFromMembers.AddConstructorParametersFromMembersCodeRefactoringProvider) Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.AddConstructorParametersFromMembers - Public Class AddConstructorParametersFromMembersTests - Inherits AbstractVisualBasicCodeActionTest - - Protected Overrides Function CreateCodeRefactoringProvider(workspace As Workspace, parameters As TestParameters) As CodeRefactoringProvider - Return New AddConstructorParametersFromMembersCodeRefactoringProvider() - End Function - - Protected Overrides Function MassageActions(actions As ImmutableArray(Of CodeAction)) As ImmutableArray(Of CodeAction) - Return FlattenActions(actions) - End Function + Public Class AddConstructorParametersFromMembersTests Public Async Function TestAdd1() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program [|Private i As Integer Private s As String|] Public Sub New(i As Integer) Me.i = i End Sub -End Class", +End Class" + Dim fixedSource = "Class Program Private i As Integer Private s As String @@ -39,21 +30,171 @@ End Class", Me.i = i Me.s = s End Sub -End Class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + + End Function + + + + Public Async Function TestProperlyWrapParameters1() As Task + Dim source = +"Class Program + [|Private i As Integer + Private s As String|] + Public Sub New( + i As Integer) + Me.i = i + End Sub +End Class" + Dim fixedSource = +"Class Program + Private i As Integer + Private s As String + Public Sub New( + i As Integer, s As String) + Me.i = i + Me.s = s + End Sub +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function + + + + Public Async Function TestProperlyWrapParameters2() As Task + Dim source = +"Class Program + [|Private i As Integer + Private s As String + Private b As Boolean|] + Public Sub New( + i As Integer, + s As String) + Me.i = i + Me.s = s + End Sub +End Class" + Dim fixedSource = +"Class Program + Private i As Integer + Private s As String + Private b As Boolean + Public Sub New( + i As Integer, + s As String, + b As Boolean) + Me.i = i + Me.s = s + Me.b = b + End Sub +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer, String)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function + + + + Public Async Function TestProperlyWrapParameters3() As Task + Dim source = +"Class Program + [|Private i As Integer + Private s As String + Private b As Boolean|] + Public Sub New(i As Integer, + s As String) + Me.i = i + Me.s = s + End Sub +End Class" + Dim fixedSource = +"Class Program + Private i As Integer + Private s As String + Private b As Boolean + Public Sub New(i As Integer, + s As String, + b As Boolean) + Me.i = i + Me.s = s + Me.b = b + End Sub +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer, String)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function + + + + Public Async Function TestProperlyWrapParameters4() As Task + Dim source = +"Class Program + [|Private i As Integer + Private s As String + Private b As Boolean|] + Public Sub New(i As Integer, + s As String) + Me.i = i + Me.s = s + End Sub +End Class" + Dim fixedSource = +"Class Program + Private i As Integer + Private s As String + Private b As Boolean + Public Sub New(i As Integer, + s As String, + b As Boolean) + Me.i = i + Me.s = s + Me.b = b + End Sub +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer, String)"), codeAction.Title) + End Sub + Await test.RunAsync() End Function Public Async Function TestAddOptional1() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program [|Private i As Integer Private s As String|] Public Sub New(i As Integer) Me.i = i End Sub -End Class", +End Class" + Dim fixedSource = "Class Program Private i As Integer Private s As String @@ -61,7 +202,16 @@ End Class", Me.i = i Me.s = s End Sub -End Class", index:=1, title:=String.Format(FeaturesResources.Add_optional_parameters_to_0, "Program(Integer)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionIndex = 1 + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_optional_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function @@ -69,7 +219,7 @@ End Class", index:=1, title:=String.Format(FeaturesResources.Add_optional_parame Public Async Function TestAddToConstructorWithMostMatchingParameters1() As Task ' behavior change with 33603, now all constructors offered - Await TestInRegularAndScriptAsync( + Dim source = "Class Program [|Private i As Integer Private s As String @@ -81,7 +231,8 @@ End Class", index:=1, title:=String.Format(FeaturesResources.Add_optional_parame Me.New(i) Me.s = s End Sub -End Class", +End Class" + Dim fixedSource = "Class Program Private i As Integer Private s As String @@ -94,7 +245,16 @@ End Class", Me.s = s Me.b = b End Sub -End Class", index:=1, title:=String.Format(FeaturesResources.Add_to_0, "Program(Integer, String)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionIndex = 1 + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_to_0, "Program(Integer, String)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function @@ -102,7 +262,7 @@ End Class", index:=1, title:=String.Format(FeaturesResources.Add_to_0, "Program( Public Async Function TestAddOptionalToConstructorWithMostMatchingParameters1() As Task ' behavior change with 33603, now all constructors offered - Await TestInRegularAndScriptAsync( + Dim source = "Class Program [|Private i As Integer Private s As String @@ -114,7 +274,8 @@ End Class", index:=1, title:=String.Format(FeaturesResources.Add_to_0, "Program( Me.New(i) Me.s = s End Sub -End Class", +End Class" + Dim fixedSource = "Class Program Private i As Integer Private s As String @@ -127,13 +288,22 @@ End Class", Me.s = s Me.b = b End Sub -End Class", index:=3, title:=String.Format(FeaturesResources.Add_to_0, "Program(Integer, String)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionIndex = 3 + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_to_0, "Program(Integer, String)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestAddParamtersToConstructorBySelectOneMember() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program Private i As Integer [|Private k As Integer|] @@ -142,7 +312,8 @@ End Class", index:=3, title:=String.Format(FeaturesResources.Add_to_0, "Program( Me.i = i Me.j = j End Sub -End Class", +End Class" + Dim fixedSource = "Class Program Private i As Integer Private k As Integer @@ -152,13 +323,18 @@ End Class", Me.j = j Me.k = k End Sub -End Class") +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + Await test.RunAsync() + End Function Public Async Function TestParametersAreStillRightIfMembersAreOutOfOrder() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program [|Private i As Integer Private k As Integer @@ -167,7 +343,8 @@ End Class") Me.i = i Me.j = j End Sub -End Class", +End Class" + Dim fixedSource = "Class Program [|Private i As Integer Private k As Integer @@ -177,20 +354,26 @@ End Class", Me.j = j Me.k = k End Sub -End Class") +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + Await test.RunAsync() + End Function Public Async Function TestNormalProperty() As Task - Await TestInRegularAndScriptAsync( + Dim source = " Class Program [|Private i As Integer Property Hello As Integer = 1|] Public Sub New(i As Integer) End Sub -End Class", +End Class" + Dim fixedSource = " Class Program Private i As Integer @@ -199,33 +382,44 @@ Class Program Me.Hello = hello End Sub End Class" - ) + + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + Await test.RunAsync() + End Function Public Async Function TestMissingIfFieldsAndPropertyAlreadyExists() As Task - Await TestMissingAsync( + Dim source = " Class Program [|Private i As Integer Property Hello As Integer = 1|] Public Sub New(i As Integer, hello As Integer) End Sub -End Class") +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = source + Await test.RunAsync() + End Function Public Async Function TestConstructorWithNoParameters() As Task - Await TestInRegularAndScriptAsync( + Dim source = " Class Program [|Private i As Integer Property Hello As Integer = 1|] Public Sub New() End Sub -End Class", +End Class" + Dim fixedSource = " Class Program [|Private i As Integer @@ -235,31 +429,41 @@ Class Program Me.Hello = hello End Sub End Class" -) + + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + Await test.RunAsync() + End Function Public Async Function TestDefaultConstructor() As Task - Await TestMissingAsync( + Dim source = " Class Program [|Private i As Integer|] End Class" -) + + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = source + Await test.RunAsync() End Function Public Async Function TestPartialSelection() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program Private i As Integer Private [|s|] As String Public Sub New(i As Integer) Me.i = i End Sub -End Class", +End Class" + Dim fixedSource = "Class Program Private i As Integer Private s As String @@ -267,13 +471,18 @@ End Class", Me.i = i Me.s = s End Sub -End Class") +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + Await test.RunAsync() + End Function Public Async Function TestMultiplePartialSelection() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program Private i As Integer Private [|s As String @@ -281,7 +490,8 @@ End Class") Public Sub New(i As Integer) Me.i = i End Sub -End Class", +End Class" + Dim fixedSource = "Class Program Private i As Integer Private s As String @@ -291,13 +501,18 @@ End Class", Me.s = s Me.j = j End Sub -End Class") +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + Await test.RunAsync() + End Function Public Async Function TestMultiplePartialSelection2() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program Private i As Integer Private [|s As String @@ -305,7 +520,8 @@ End Class") Public Sub New(i As Integer) Me.i = i End Sub -End Class", +End Class" + Dim fixedSource = "Class Program Private i As Integer Private s As String @@ -314,14 +530,20 @@ End Class", Me.i = i Me.s = s End Sub -End Class") +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + Await test.RunAsync() + End Function Public Async Function TestMultipleConstructors_FirstOfThree() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program + Private i as Integer Private [|l|] As Integer Public Sub New(i As Integer) @@ -333,11 +555,13 @@ End Class") Public Sub New(i As Integer, j As Integer, k As Integer) End Sub -End Class", +End Class" + Dim fixedSource = "Class Program + Private i as Integer Private [|l|] As Integer - Public Sub New(i As Integer, l As Integer) + Public Sub {|BC30269:New|}(i As Integer, l As Integer) Me.i = i Me.l = l End Sub @@ -347,14 +571,23 @@ End Class", Public Sub New(i As Integer, j As Integer, k As Integer) End Sub -End Class", index:=0, title:=String.Format(FeaturesResources.Add_to_0, "Program(Integer)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestMultipleConstructors_SecondOfThree() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program + Private i as Integer Private [|l|] As Integer Public Sub New(i As Integer) @@ -366,28 +599,40 @@ End Class", index:=0, title:=String.Format(FeaturesResources.Add_to_0, "Program( Public Sub New(i As Integer, j As Integer, k As Integer) End Sub -End Class", +End Class" + Dim fixedSource = "Class Program + Private i as Integer Private [|l|] As Integer Public Sub New(i As Integer) Me.i = i End Sub - Public Sub New(i As Integer, j As Integer, l As Integer) + Public Sub {|BC30269:New|}(i As Integer, j As Integer, l As Integer) Me.l = l End Sub Public Sub New(i As Integer, j As Integer, k As Integer) End Sub -End Class", index:=1, title:=String.Format(FeaturesResources.Add_to_0, "Program(Integer, Integer)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionIndex = 1 + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_to_0, "Program(Integer, Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestMultipleConstructors_ThirdOfThree() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program + Private i as Integer Private [|l|] As Integer Public Sub New(i As Integer) @@ -399,8 +644,10 @@ End Class", index:=1, title:=String.Format(FeaturesResources.Add_to_0, "Program( Public Sub New(i As Integer, j As Integer, k As Integer) End Sub -End Class", +End Class" + Dim fixedSource = "Class Program + Private i as Integer Private [|l|] As Integer Public Sub New(i As Integer) @@ -413,14 +660,24 @@ End Class", Public Sub New(i As Integer, j As Integer, k As Integer, l As Integer) Me.l = l End Sub -End Class", index:=2, title:=String.Format(FeaturesResources.Add_to_0, "Program(Integer, Integer, Integer)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionIndex = 2 + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_to_0, "Program(Integer, Integer, Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestMultipleConstructors_OneMustBeOptional() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program + Private i as Integer Private [|l|] As Integer ' index 0 as required @@ -437,8 +694,10 @@ End Class", index:=2, title:=String.Format(FeaturesResources.Add_to_0, "Program( ' index 4 as optional Public Sub New(i As Integer, j As Double) End Sub -End Class", +End Class" + Dim fixedSource = "Class Program + Private i as Integer Private [|l|] As Integer ' index 0 as required @@ -456,14 +715,24 @@ End Class", Public Sub New(i As Integer, j As Double, l As Integer) Me.l = l End Sub -End Class", index:=1, title:=String.Format(FeaturesResources.Add_to_0, "Program(Integer, Double)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionIndex = 1 + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_to_0, "Program(Integer, Double)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestMultipleConstructors_OneMustBeOptional2() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program + Private i as Integer Private [|l|] As Integer ' index 0, and 2 as optional @@ -478,8 +747,10 @@ End Class", index:=1, title:=String.Format(FeaturesResources.Add_to_0, "Program( ' index 1, and 4 as optional Public Sub New(i As Integer, j As Double) End Sub -End Class", +End Class" + Dim fixedSource = "Class Program + Private i as Integer Private [|l|] As Integer ' index 0, and 2 as optional @@ -495,14 +766,24 @@ End Class", ' index 1, and 4 as optional Public Sub New(i As Integer, j As Double) End Sub -End Class", index:=3, title:=String.Format(FeaturesResources.Add_to_0, "Program(Double)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionIndex = 3 + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_to_0, "Program(Double)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestMultipleConstructors_AllMustBeOptional1() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program + Private i as Integer Private [|p|] As Integer Public Sub New(Optional i As Integer = Nothing) @@ -514,8 +795,10 @@ End Class", index:=3, title:=String.Format(FeaturesResources.Add_to_0, "Program( Public Sub New(l As Integer, m As Integer, Optional n As Integer = Nothing) End Sub -End Class", +End Class" + Dim fixedSource = "Class Program + Private i as Integer Private p As Integer Public Sub New(Optional i As Integer = Nothing, Optional p As Integer = Nothing) @@ -528,14 +811,23 @@ End Class", Public Sub New(l As Integer, m As Integer, Optional n As Integer = Nothing) End Sub -End Class", index:=0, title:=String.Format(FeaturesResources.Add_to_0, "Program(Integer)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestMultipleConstructors_AllMustBeOptional2() As Task - Await TestInRegularAndScriptAsync( + Dim source = "Class Program + Private i as Integer Private [|p|] As Integer Public Sub New(Optional i As Integer = Nothing) @@ -547,8 +839,10 @@ End Class", index:=0, title:=String.Format(FeaturesResources.Add_to_0, "Program( Public Sub New(l As Integer, m As Integer, Optional n As Integer = Nothing) End Sub -End Class", +End Class" + Dim fixedSource = "Class Program + Private i as Integer Private p As Integer Public Sub New(Optional i As Integer = Nothing) @@ -561,13 +855,22 @@ End Class", Public Sub New(l As Integer, m As Integer, Optional n As Integer = Nothing, Optional p As Integer = Nothing) Me.p = p End Sub -End Class", index:=2, title:=String.Format(FeaturesResources.Add_to_0, "Program(Integer, Integer, Integer)")) +End Class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionIndex = 2 + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_to_0, "Program(Integer, Integer, Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function - public async function TestNonSelection1() As Task - Await TestInRegularAndScriptAsync( + Public Async Function TestNonSelection1() As Task + Dim source = "imports System.Collections.Generic class Program @@ -577,7 +880,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collections.Generic class Program @@ -588,13 +892,21 @@ class Program Me.i = i Me.s = s end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelection2() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collections.Generic class Program @@ -604,7 +916,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collections.Generic class Program @@ -615,13 +928,21 @@ class Program Me.i = i Me.s = s end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelection3() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collections.Generic class Program @@ -631,7 +952,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collections.Generic class Program @@ -642,13 +964,21 @@ class Program Me.i = i Me.s = s end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelection4() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collections.Generic class Program @@ -658,7 +988,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collections.Generic class Program @@ -669,13 +1000,21 @@ class Program Me.i = i Me.s = s end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelection5() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collections.Generic class Program @@ -685,7 +1024,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collections.Generic class Program @@ -696,13 +1036,21 @@ class Program Me.i = i Me.s = s end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMultiVar1() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program @@ -712,7 +1060,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collection.Generic class Program @@ -724,13 +1073,21 @@ class Program Me.s = s Me.t = t end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMultiVar2() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program @@ -740,7 +1097,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collection.Generic class Program @@ -752,13 +1110,21 @@ class Program Me.s = s Me.t = t end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMultiVar3() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program @@ -768,7 +1134,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collection.Generic class Program @@ -779,13 +1146,21 @@ class Program Me.i = i Me.s = s end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMultiVar4() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program @@ -795,7 +1170,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collection.Generic class Program @@ -806,13 +1182,21 @@ class Program Me.i = i Me.s = s end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMultiVar5() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program @@ -822,7 +1206,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collection.Generic class Program @@ -833,13 +1218,21 @@ class Program Me.i = i Me.t = t end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMultiVar6() As Task - Await TestInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program @@ -849,7 +1242,8 @@ class Program public sub new(i As Integer) Me.i = i end sub -end class", +end class" + Dim fixedSource = "imports System.Collection.Generic class Program @@ -860,13 +1254,21 @@ class Program Me.i = i Me.t = t end sub -end class", title:=String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)")) +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = fixedSource + test.CodeActionVerifier = Sub(codeAction As CodeAction, verifier As IVerifier) + verifier.Equal(String.Format(FeaturesResources.Add_parameters_to_0, "Program(Integer)"), codeAction.Title) + End Sub + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMissing1() As Task - Await TestMissingInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program @@ -877,30 +1279,39 @@ class Program public sub new(i As Integer) Me.i = i end sub -}") +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = source + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMissing2() As Task - Await TestMissingInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program -{ dim i As Integer d[||]im s, t As String public sub new(i As Integer) Me.i = i end sub -}") +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = source + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMissing3() As Task - Await TestMissingInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program @@ -908,16 +1319,20 @@ class Program dim[||] s, t As String public sub new(i As Integer) - { Me.i = i end sub -}") +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = source + Await test.RunAsync() + End Function Public Async Function TestNonSelectionMissing4() As Task - Await TestMissingInRegularAndScriptAsync( + Dim source = "imports System.Collection.Generic class Program @@ -927,7 +1342,12 @@ class Program public sub new(i As Integer) Me.i = i end sub -}") +end class" + Dim test As New VerifyVB.Test() + test.TestCode = source + test.FixedCode = source + Await test.RunAsync() + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb b/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb index 3435ad3a48814..3ef31c1fa05ec 100644 --- a/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.CodeCleanup.Providers Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Formatting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CaseCorrecting <[UseExportProvider]> @@ -33,10 +34,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CaseCorrecting Dim buffer = hostDocument.GetTextBuffer() Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) Dim span = (Await document.GetSyntaxRootAsync()).FullSpan + Dim options = Await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None) Dim service = document.GetLanguageService(Of ICodeCleanerService) Dim newDocument = Await service.CleanupAsync( - document, ImmutableArray.Create(span), + document, ImmutableArray.Create(span), options, ImmutableArray.Create(Of ICodeCleanupProvider)(New CaseCorrectionCodeCleanupProvider()), CancellationToken.None) diff --git a/src/EditorFeatures/VisualBasicTest/Classification/SemanticClassifierTests.vb b/src/EditorFeatures/VisualBasicTest/Classification/SemanticClassifierTests.vb index 073776aead0e6..addc3258329f2 100644 --- a/src/EditorFeatures/VisualBasicTest/Classification/SemanticClassifierTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Classification/SemanticClassifierTests.vb @@ -6,6 +6,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.Classification Imports Microsoft.CodeAnalysis.Editor.UnitTests.Classification.FormattedClassifications Imports Microsoft.CodeAnalysis.Remote.Testing +Imports Microsoft.CodeAnalysis.Test.Utilities.EmbeddedLanguages Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Classification @@ -625,6 +626,123 @@ Regex.Quantifier("?"), Regex.Anchor("^")) End Function + + Public Async Function TestRegexStringSyntaxAttribute_Field(testHost As TestHost) As Task + Await TestAsync( +" +imports System.Diagnostics.CodeAnalysis +imports System.Text.RegularExpressions + +class Program + + dim field as string + + sub Goo() + [|me.field = ""$(\b\G\z)""|] + end sub +end class" & EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeVB, + testHost, +Field("field"), +Regex.Anchor("$"), +Regex.Grouping("("), +Regex.Anchor("\"), +Regex.Anchor("b"), +Regex.Anchor("\"), +Regex.Anchor("G"), +Regex.Anchor("\"), +Regex.Anchor("z"), +Regex.Grouping(")")) + End Function + + + Public Async Function TestRegexStringSyntaxAttribute_Attribute(testHost As TestHost) As Task + Await TestAsync( +" +imports system +imports System.Diagnostics.CodeAnalysis +imports System.Text.RegularExpressions + + +class RegexTestAttribute + inherits Attribute + + public sub new( value as string) + end sub +end class + +class Program + [||] + dim field as string +end class" & EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeVB, + testHost, +[Class]("RegexTest"), +Regex.Anchor("$"), +Regex.Grouping("("), +Regex.Anchor("\"), +Regex.Anchor("b"), +Regex.Anchor("\"), +Regex.Anchor("G"), +Regex.Anchor("\"), +Regex.Anchor("z"), +Regex.Grouping(")")) + End Function + + + Public Async Function TestRegexStringSyntaxAttribute_Property(testHost As TestHost) As Task + Await TestAsync( +" +imports System.Diagnostics.CodeAnalysis +imports System.Text.RegularExpressions + +class Program + + property prop as string + + sub Goo() + [|me.prop = ""$(\b\G\z)""|] + end sub +end class" & EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeVB, + testHost, +[Property]("prop"), +Regex.Anchor("$"), +Regex.Grouping("("), +Regex.Anchor("\"), +Regex.Anchor("b"), +Regex.Anchor("\"), +Regex.Anchor("G"), +Regex.Anchor("\"), +Regex.Anchor("z"), +Regex.Grouping(")")) + End Function + + + Public Async Function TestRegexStringSyntaxAttribute_Sub(testHost As TestHost) As Task + Await TestAsync( +" +imports System.Diagnostics.CodeAnalysis +imports System.Text.RegularExpressions + +class Program + sub M(p as string) + end sub + + sub Goo() + [|M(""$(\b\G\z)"")|] + end sub +end class" & EmbeddedLanguagesTestConstants.StringSyntaxAttributeCodeVB, + testHost, +Method("M"), +Regex.Anchor("$"), +Regex.Grouping("("), +Regex.Anchor("\"), +Regex.Anchor("b"), +Regex.Anchor("\"), +Regex.Anchor("G"), +Regex.Anchor("\"), +Regex.Anchor("z"), +Regex.Grouping(")")) + End Function + Public Async Function TestConstField(testHost As TestHost) As Task Dim code = diff --git a/src/EditorFeatures/VisualBasicTest/Completion/ArgumentProviders/AbstractVisualBasicArgumentProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/ArgumentProviders/AbstractVisualBasicArgumentProviderTests.vb index 75d3678e35751..b5eb9fe055c5c 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/ArgumentProviders/AbstractVisualBasicArgumentProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/ArgumentProviders/AbstractVisualBasicArgumentProviderTests.vb @@ -2,11 +2,18 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Test.Utilities.Completion +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.ArgumentProviders Public MustInherit Class AbstractVisualBasicArgumentProviderTests Inherits AbstractArgumentProviderTests(Of VisualBasicTestWorkspaceFixture) + + Protected Overrides Function GetArgumentList(token As SyntaxToken) As (argumentList As SyntaxNode, arguments As ImmutableArray(Of SyntaxNode)) + Dim argumentList = token.GetRequiredParent().GetAncestorsOrThis(Of ArgumentListSyntax)().First() + Return (argumentList, argumentList.Arguments.Cast(Of SyntaxNode)().ToImmutableArray()) + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/Completion/ArgumentProviders/ContextVariableArgumentProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/ArgumentProviders/ContextVariableArgumentProviderTests.vb index 57cb3b0a273f2..e93ae272337e6 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/ArgumentProviders/ContextVariableArgumentProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/ArgumentProviders/ContextVariableArgumentProviderTests.vb @@ -55,19 +55,23 @@ End Class End Function - - - - Public Async Function TestInstanceVariable(type As String) As Task + + + + + + Public Async Function TestInstanceVariable(fieldType As String, parameterType As String) As Task Dim markup = $" +Imports System.Collections.Generic + Class C - Dim arg As {type} + Dim arg As {fieldType} Sub Method() Me.Target($$) End Sub - Sub Target(arg As {type}) + Sub Target(arg As {parameterType}) End Sub End Class " @@ -76,6 +80,79 @@ End Class Await VerifyDefaultValueAsync(markup, expectedDefaultValue:=Nothing, previousDefaultValue:="prior") End Function + + + + + Public Async Function TestMeInstance(parameterType As String) As Task + Dim markup = $" +Imports System.Collections.Generic + +Interface I : End Interface +Class B : End Class + +Class C + Inherits B + Implements I + + Sub Method() + Me.Target($$) + End Sub + + Sub Target(arg As {parameterType}) + End Sub +End Class +" + + Await VerifyDefaultValueAsync(markup, "Me") + Await VerifyDefaultValueAsync(markup, expectedDefaultValue:=Nothing, previousDefaultValue:="prior") + End Function + + + + + Public Async Function TestMeInstanceNotProvided1(parameterType As String) As Task + Dim markup = $" +Imports System.Collections.Generic + +Interface I : End Interface +Class B : End Class + +Class C + Inherits B + Implements I + + Sub Method() + Me.Target($$) + End Sub + + Sub Target(arg As {parameterType}) + End Sub +End Class +" + + Await VerifyDefaultValueAsync(markup, Nothing) + End Function + + + Public Async Function TestMeInstanceNotProvided2() As Task + Dim markup = $" +Imports System.Collections.Generic + +Class C + + Shared Sub Method() + Target($$) + End Sub + + Shared Sub Target(arg As C) + End Sub +End Class +" + + Await VerifyDefaultValueAsync(markup, Nothing) + End Function + ' Note: The current implementation checks for exact type and name match. If this changes, some of these tests ' may need to be updated to account for the new behavior. diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.vb index be4ed18f09a9a..78cb7524973ab 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.vb @@ -14,8 +14,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Public Sub New() ShowImportCompletionItemsOptionValue = True - IsExpandedCompletion = True - TimeoutInMilliseconds = -1 ' -1 would disable timebox + ForceExpandedCompletionIndexCreation = True End Sub Friend Overrides Function GetCompletionProviderType() As Type diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb index eb2636346cdd2..b012dc1a2a484 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb @@ -461,7 +461,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 Is Nothing OrElse completionList.GetTestAccessor().IsExclusive, "Expected always exclusive") + Assert.True(completionList.IsEmpty OrElse completionList.GetTestAccessor().IsExclusive, "Expected always exclusive") End Using End Function diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.vb index 16f60030239e9..6921e1eab8687 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SuggestionModeCompletionProviderTests.vb @@ -375,11 +375,12 @@ End Class workspaceFixture.GetWorkspace(ExportProvider) Dim document1 = workspaceFixture.UpdateDocument(code, SourceCodeKind.Regular) - Dim options = CompletionOptions.From(document1.Project.Solution.Options, document1.Project.Language) + Dim options As CompletionOptions If useDebuggerOptions Then - options.FilterOutOfScopeLocals = False - options.ShowXmlDocCommentCompletion = False + options = New CompletionOptions(FilterOutOfScopeLocals:=False, ShowXmlDocCommentCompletion:=False) + Else + options = CompletionOptions.Default End If Await CheckResultsAsync(document1, position, isBuilder, triggerInfo, options) diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.vb index a82ccaab0d7c9..5e9b9dd20e920 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.vb @@ -14,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Public Sub New() ShowImportCompletionItemsOptionValue = True - IsExpandedCompletion = True + ForceExpandedCompletionIndexCreation = True End Sub Friend Overrides Function GetCompletionProviderType() As Type diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb index f4db5fc18d4d2..5014dfda6a901 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Packaging Imports Microsoft.CodeAnalysis.Shared.Utilities Imports Microsoft.CodeAnalysis.SymbolSearch @@ -25,9 +26,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp ImmutableArray.Create(New PackageSource(PackageSourceHelper.NugetOrgSourceName, "http://nuget.org")) Protected Overrides Sub InitializeWorkspace(workspace As TestWorkspace, parameters As TestParameters) - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options. - WithChangedOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages, LanguageNames.VisualBasic, True). - WithChangedOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.VisualBasic, True))) + workspace.GlobalOptions.SetGlobalOption(New OptionKey(SymbolSearchOptionsStorage.SearchNuGetPackages, LanguageNames.VisualBasic), True) + workspace.GlobalOptions.SetGlobalOption(New OptionKey(SymbolSearchOptionsStorage.SearchReferenceAssemblies, LanguageNames.VisualBasic), True) End Sub Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/Configuration/ConfigureSeverity/DotNetDiagnosticSeverityBasedSeverityConfigurationTests.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/Configuration/ConfigureSeverity/DotNetDiagnosticSeverityBasedSeverityConfigurationTests.vb index e3263737e8f5e..610ef32864f02 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/Configuration/ConfigureSeverity/DotNetDiagnosticSeverityBasedSeverityConfigurationTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/Configuration/ConfigureSeverity/DotNetDiagnosticSeverityBasedSeverityConfigurationTests.vb @@ -195,6 +195,98 @@ End Class [*.vb] dotnet_diagnostic.XYZ1111.severity = none +# XYZ0001: Title +dotnet_diagnostic.XYZ0001.severity = none + + +" + Await TestInRegularAndScriptAsync(input, expected, CodeActionIndex) + End Function + + + Public Async Function ConfigureGlobalconfig_Empty_None() As Task + Dim input = " + + + +[|Class Program1 +End Class|] + + is_global = true + +" + Dim expected = " + + + +Class Program1 +End Class + + is_global = true + +# XYZ0001: Title +dotnet_diagnostic.XYZ0001.severity = none + + +" + Await TestInRegularAndScriptAsync(input, expected, CodeActionIndex) + End Function + + + Public Async Function ConfigureGlobalconfig_RuleExists_None() As Task + Dim input = " + + + +[|Class Program1 +End Class|] + + is_global = true # Comment +dotnet_diagnostic.XYZ0001.severity = suggestion # Comment + + +" + Dim expected = " + + + +Class Program1 +End Class + + is_global = true # Comment +dotnet_diagnostic.XYZ0001.severity = none # Comment + + +" + Await TestInRegularAndScriptAsync(input, expected, CodeActionIndex) + End Function + + + Public Async Function ConfigureGlobalconfig_InvalidHeader_None() As Task + Dim input = " + + + +[|Class Program1 +End Class|] + + [*.cs] +dotnet_diagnostic.XYZ0001.severity = suggestion + + +" + Dim expected = " + + + +Class Program1 +End Class + + [*.cs] +dotnet_diagnostic.XYZ0001.severity = suggestion + +[*.vb] + # XYZ0001: Title dotnet_diagnostic.XYZ0001.severity = none diff --git a/src/EditorFeatures/VisualBasicTest/EditAndContinue/LineEditTests.vb b/src/EditorFeatures/VisualBasicTest/EditAndContinue/LineEditTests.vb index f9ce4e1dedf6c..c6f9b72786ef0 100644 --- a/src/EditorFeatures/VisualBasicTest/EditAndContinue/LineEditTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EditAndContinue/LineEditTests.vb @@ -73,7 +73,7 @@ End Class edits.VerifyLineEdits( { New SourceLineUpdate(2, 6), - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(5), + New SourceLineUpdate(5, 5), New SourceLineUpdate(6, 2) }, {}) End Sub @@ -118,9 +118,9 @@ End Class edits.VerifyLineEdits( { New SourceLineUpdate(2, 6), - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(6), + New SourceLineUpdate(6, 6), New SourceLineUpdate(7, 2), - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(10) + New SourceLineUpdate(10, 10) }, {}) End Sub @@ -1295,7 +1295,7 @@ End Class { New SequencePointUpdates("a", ImmutableArray.Create( New SourceLineUpdate(1, 11), ' x, y, F1, F2 - AbstractEditAndContinueAnalyzer.CreateZeroDeltaSourceLineUpdate(5),' lines between F2 And D ctor + New SourceLineUpdate(5, 5),' lines between F2 And D ctor New SourceLineUpdate(7, 17)))' D ctor }, semanticEdits:= diff --git a/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateJsonStringTests.vb b/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateJsonStringTests.vb new file mode 100644 index 0000000000000..29a775d333ee0 --- /dev/null +++ b/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateJsonStringTests.vb @@ -0,0 +1,218 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports Microsoft.CodeAnalysis.CodeFixes +Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions +Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics +Imports Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages +Imports Xunit.Abstractions + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EmbeddedLanguages + Public Class ValidateJsonStringTests + Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest + + Public Sub New(logger As ITestOutputHelper) + MyBase.New(logger) + End Sub + + Friend Overrides Function CreateDiagnosticProviderAndFixer(Workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) + Return (New VisualBasicJsonDiagnosticAnalyzer(), Nothing) + End Function + + Private Shared Function OptionOn() As OptionsCollection + Dim result = New OptionsCollection(LanguageNames.VisualBasic) + result.Add(JsonFeatureOptions.ReportInvalidJsonPatterns, True) + Return result + End Function + + + Public Async Function TestWarning1() As Task + Await TestDiagnosticInfoAsync(" +class Program + sub Main() + ' lang=json,strict + dim r = ""[|new|] Json()"" + end sub +end class", + options:=OptionOn(), + diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity:=DiagnosticSeverity.Warning, + diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, FeaturesResources.Constructors_not_allowed)) + End Function + + + Public Async Function TestWarning2() As Task + Await TestDiagnosticInfoAsync(" +class Program + sub Main() + ' lang=json + dim r = ""[|}|]"" + end sub +end class", + options:=OptionOn(), + diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity:=DiagnosticSeverity.Warning, + diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, + String.Format(FeaturesResources._0_unexpected, "}"))) + End Function + + + Public Async Function TestJsonDocumentWithTrailingComma() As Task + Await TestDiagnosticInfoAsync(" + + +imports System.Text.Json + +class Program + sub Main() + dim r = JsonDocument.Parse(""[1[|,|]]"") + end sub +end class + + +", + options:=OptionOn(), + diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity:=DiagnosticSeverity.Warning, + diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Trailing_comma_not_allowed)) + End Function + + + Public Async Function TestJsonDocumentTrailingCommaDisallowed() As Task + Await TestDiagnosticInfoAsync(" + + +imports System.Text.Json + +class Program + sub Main() + dim r = JsonDocument.Parse(""[1[|,|]]"", new JsonDocumentOptions() with { .AllowTrailingCommas = false }) + end sub +end class + + +", + options:=OptionOn(), + diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity:=DiagnosticSeverity.Warning, + diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Trailing_comma_not_allowed)) + End Function + + + Public Async Function TestJsonDocumentTrailingCommaAllowed() As Task + Await TestDiagnosticMissingAsync(" + + +imports System.Text.Json + +class Program + sub Main() + dim r = JsonDocument.Parse(""[1[|,|]]"", new JsonDocumentOptions() with { .AllowTrailingCommas = true }) + end sub +end class + + +") + End Function + + + Public Async Function TestJsonDocumentTrailingCommaAllowedCaseChange() As Task + Await TestDiagnosticMissingAsync(" + + +imports System.Text.Json + +class Program + sub Main() + dim r = JsonDocument.Parse(""[1[|,|]]"", new jsondocumentoptions() with { .allowTrailingCommas = true }) + end sub +end class + + +") + End Function + + + Public Async Function TestJsonDocumentWithComments() As Task + Await TestDiagnosticInfoAsync(" + + +imports System.Text.Json + +class Program + sub Main() + dim r = JsonDocument.Parse(""[1][|/*comment*/|]"") + end sub +end class + + +", + options:=OptionOn(), + diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity:=DiagnosticSeverity.Warning, + diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Comments_not_allowed)) + End Function + + + Public Async Function TestJsonDocumentCommentsDisallowed() As Task + Await TestDiagnosticInfoAsync(" + + +imports System.Text.Json + +class Program + sub Main() + dim r = JsonDocument.Parse(""[1][|/*comment*/|]"", new JsonDocumentOptions() with { .CommentHandling = JsonCommentHandling.Disallow }) + end sub +end class + + +", + options:=OptionOn(), + diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, + diagnosticSeverity:=DiagnosticSeverity.Warning, + diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, + FeaturesResources.Comments_not_allowed)) + End Function + + + Public Async Function TestJsonDocumentCommentsAllowed() As Task + Await TestDiagnosticMissingAsync(" + + +imports System.Text.Json + +class Program + sub Main() + dim r = JsonDocument.Parse(""[1][|/*comment*/|]"", new JsonDocumentOptions() with { .CommentHandling = JsonCommentHandling.Allow }) + end sub +end class + + +") + End Function + + + Public Async Function TestJsonDocumentCommentsAllowedCaseInsensitive() As Task + Await TestDiagnosticMissingAsync(" + + +imports System.Text.Json + +class Program + sub Main() + dim r = jsonDocument.parse(""[1][|/*comment*/|]"", new jsonDocumentOptions() with { .commentHandling = jsonCommentHandling.allow }) + end sub +end class + + +") + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateRegexStringTests.vb b/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateRegexStringTests.vb index ebdee60a2c885..98ea8ae6a5684 100644 --- a/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateRegexStringTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateRegexStringTests.vb @@ -6,8 +6,7 @@ Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics -Imports Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions -Imports Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions +Imports Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices Imports Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EmbeddedLanguages diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb index 78406bfccc6cc..88eba07274574 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Diagnostics.VisualBasic @@ -328,6 +329,8 @@ End Class Optional systemImportsFirst As Boolean = True, Optional separateImportsGroups As Boolean = False) As Task Using workspace = TestWorkspace.CreateVisualBasic(code, composition:=EditorTestCompositions.EditorFeaturesWpf) + Dim options = CodeActionOptions.Default + Dim solution = workspace.CurrentSolution _ .WithOptions(workspace.Options _ .WithChangedOption(GenerationOptions.PlaceSystemNamespaceFirst, @@ -355,10 +358,12 @@ End Class Dim enabledDiagnostics = codeCleanupService.GetAllDiagnostics() - Dim newDoc = Await codeCleanupService.CleanupAsync(document, - enabledDiagnostics, - New ProgressTracker, - CancellationToken.None) + Dim newDoc = Await codeCleanupService.CleanupAsync( + document, + enabledDiagnostics, + New ProgressTracker, + options, + CancellationToken.None) Dim actual = Await newDoc.GetTextAsync() diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartTokenFormatter_FormatTokenTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartTokenFormatter_FormatTokenTests.vb index 13f9f9c369a03..82ed93b5b91c6 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartTokenFormatter_FormatTokenTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/Indentation/SmartTokenFormatter_FormatTokenTests.vb @@ -179,9 +179,6 @@ End Class MarkupTestFile.GetPosition(codeWithMarkup, code, position) Using workspace = TestWorkspace.CreateVisualBasic(code) - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(FormattingOptions.SmartIndent, LanguageNames.VisualBasic, indentStyle))) - Dim hostdoc = workspace.Documents.First() Dim buffer = hostdoc.GetTextBuffer() @@ -190,10 +187,9 @@ End Class Dim document = workspace.CurrentSolution.GetDocument(hostdoc.Id) Dim root = DirectCast(Await document.GetSyntaxRootAsync(), CompilationUnitSyntax) - Dim options = Await document.GetOptionsAsync() - Dim documentIndentStyle = options.GetOption(FormattingOptions.SmartIndent, root.Language) + Dim options = Await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None) - Dim formattingRules = New SpecialFormattingRule(documentIndentStyle).Concat(Formatter.GetDefaultFormattingRules(document)) + Dim formattingRules = New SpecialFormattingRule(indentStyle).Concat(Formatter.GetDefaultFormattingRules(document)) ' get token Dim token = root.FindToken(position) @@ -201,14 +197,12 @@ End Class Dim previousToken = token.GetPreviousToken(includeZeroWidth:=True) Dim ignoreMissingToken = previousToken.IsMissing AndAlso line.Start.Position = position - Dim optionService = workspace.Services.GetRequiredService(Of IOptionService)() - Assert.True(VisualBasicIndentationService.ShouldUseSmartTokenFormatterInsteadOfIndenter( - formattingRules, root, line.AsTextLine, optionService, workspace.Options, - Nothing, ignoreMissingToken)) + formattingRules, root, line.AsTextLine, options, Nothing, ignoreMissingToken)) - Dim smartFormatter = New VisualBasicSmartTokenFormatter(Await document.GetOptionsAsync(CancellationToken.None), formattingRules, root) - Dim changes = Await smartFormatter.FormatTokenAsync(workspace, token, Nothing) + Dim formatOptions = Await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None) + Dim smartFormatter = New VisualBasicSmartTokenFormatter(formatOptions, formattingRules, root) + Dim changes = Await smartFormatter.FormatTokenAsync(workspace.Services, token, Nothing) Using edit = buffer.CreateEdit() For Each change In changes diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormatterTestBase.vb b/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormatterTestBase.vb index 8f292b13e5798..370541bae9212 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormatterTestBase.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormatterTestBase.vb @@ -58,11 +58,16 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Formatting End If Dim rules = formattingRuleProvider.CreateRule(document, 0).Concat(Formatter.GetDefaultFormattingRules(document)) + Dim options = Await SyntaxFormattingOptions.FromDocumentAsync(document, CancellationToken.None) Dim changes = Formatter.GetFormattedTextChanges( Await syntaxTree.GetRootAsync(), workspace.Documents.First(Function(d) d.SelectedSpans.Any()).SelectedSpans, - workspace, Await document.GetOptionsAsync(CancellationToken.None), rules, CancellationToken.None) + workspace.Services, + options, + rules, + CancellationToken.None) + AssertResult(expected, clonedBuffer, changes) End Using End Function diff --git a/src/EditorFeatures/VisualBasicTest/IntroduceUsingStatement/IntroduceUsingStatementTests.vb b/src/EditorFeatures/VisualBasicTest/IntroduceUsingStatement/IntroduceUsingStatementTests.vb index cc3e59bc32017..787ea9af6dd91 100644 --- a/src/EditorFeatures/VisualBasicTest/IntroduceUsingStatement/IntroduceUsingStatementTests.vb +++ b/src/EditorFeatures/VisualBasicTest/IntroduceUsingStatement/IntroduceUsingStatementTests.vb @@ -98,6 +98,7 @@ End Class", "Class C Sub M(disposable As System.IDisposable) Using name = disposable End Using + Dim ignore = disposable End Sub End Class") @@ -114,6 +115,7 @@ End Class", "Class C Sub M(disposable As System.IDisposable) Using name = disposable End Using + Dim ignore = disposable End Sub End Class") @@ -287,6 +289,7 @@ End Class", "Class C M(null) M(x) End Using + M(null) End Sub End Class") @@ -383,6 +386,7 @@ Class C Dim buffer = reader.GetBuffer() buffer.Clone() End Using + Dim a = 1 End Sub End Class") @@ -412,9 +416,55 @@ Class C Dim a As Integer = buffer(0), b As Integer = a Dim c = b End Using + Dim d = 1 End Sub End Class") End Function + + + + Public Async Function HandleTrailingComma() As Task + Await TestInRegularAndScriptAsync( +"Imports System +Imports System.Collections.Generic +Imports System.Linq + +Class D + Implements IDisposable + + Public Sub Dispose() Implements IDisposable.Dispose + End Sub +End Class + +Module Program + Public Property Current As Object + + Sub Main(args As String()) + Dim dt As D = New D()[||] 'This is a comment + Console.WriteLine(dt.ToString()) + End Sub +End Module", +"Imports System +Imports System.Collections.Generic +Imports System.Linq + +Class D + Implements IDisposable + + Public Sub Dispose() Implements IDisposable.Dispose + End Sub +End Class + +Module Program + Public Property Current As Object + + Sub Main(args As String()) + Using dt As D = New D() 'This is a comment + Console.WriteLine(dt.ToString()) + End Using + End Sub +End Module") + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/InvertIf/InvertMultiLineIfTests.vb b/src/EditorFeatures/VisualBasicTest/InvertIf/InvertMultiLineIfTests.vb index 8dbf14bc3d41c..5fa42a6799f2c 100644 --- a/src/EditorFeatures/VisualBasicTest/InvertIf/InvertMultiLineIfTests.vb +++ b/src/EditorFeatures/VisualBasicTest/InvertIf/InvertMultiLineIfTests.vb @@ -14,8 +14,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.InvertIf Return New VisualBasicInvertMultiLineIfCodeRefactoringProvider() End Function - Public Async Function TestFixOneAsync(initial As String, expected As String) As Task - Await TestInRegularAndScriptAsync(CreateTreeText(initial), CreateTreeText(expected)) + Public Async Function TestFixOneAsync(initial As String, expected As String, Optional parseOptions As ParseOptions = Nothing) As Task + Await TestInRegularAndScriptAsync(CreateTreeText(initial), CreateTreeText(expected), parseOptions:=parseOptions) End Function Public Shared Function CreateTreeText(initial As String) As String @@ -733,5 +733,65 @@ end class", end class") End Function + + + + Public Async Function TestMultiLineTypeOfIs_VB12() As Task + Await TestFixOneAsync( +" + [||]If TypeOf a Is String Then + aMethod() + Else + bMethod() + End If +", +" + If Not (TypeOf a Is String) Then + bMethod() + Else + aMethod() + End If +", VisualBasicParseOptions.Default.WithLanguageVersion(LanguageVersion.VisualBasic12)) + End Function + + + + Public Async Function TestMultiLineTypeOfIs_VB14() As Task + Await TestFixOneAsync( +" + [||]If TypeOf a Is String Then + aMethod() + Else + bMethod() + End If +", +" + If TypeOf a IsNot String Then + bMethod() + Else + aMethod() + End If +", VisualBasicParseOptions.Default.WithLanguageVersion(LanguageVersion.VisualBasic14)) + End Function + + + + Public Async Function TestMultiLineTypeOfIsNot() As Task + Await TestFixOneAsync( +" + [||]If TypeOf a IsNot String Then + aMethod() + Else + bMethod() + End If +", +" + If TypeOf a Is String Then + bMethod() + Else + aMethod() + End If +") + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/AccessorDeclarationHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/AccessorDeclarationHighlighterTests.vb index cfd19447911c9..e9db971b8e705 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/AccessorDeclarationHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/AccessorDeclarationHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class AccessorDeclarationHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ConditionalPreprocessorHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ConditionalPreprocessorHighlighterTests.vb index b41f6e5d2691d..afe6f52138e4d 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ConditionalPreprocessorHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ConditionalPreprocessorHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class ConditionalPreprocessorHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ConstructorDeclarationHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ConstructorDeclarationHighlighterTests.vb index 22dc187b5a700..a60d774c9e547 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ConstructorDeclarationHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ConstructorDeclarationHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class ConstructorDeclarationHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/DoLoopBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/DoLoopBlockHighlighterTests.vb index 3e4f6a149f570..a4e64fc11baa4 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/DoLoopBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/DoLoopBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class DoLoopBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EnumBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EnumBlockHighlighterTests.vb index 34ea4aae4b4bc..75433581c7af7 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EnumBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EnumBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class EnumBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EventBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EventBlockHighlighterTests.vb index 9a00ab1b2ea11..03f40bfac64b6 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EventBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EventBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class EventBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EventDeclarationHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EventDeclarationHighlighterTests.vb index 6acda27f4fe91..bd307fd51aa03 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EventDeclarationHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/EventDeclarationHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class EventDeclarationHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ForLoopBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ForLoopBlockHighlighterTests.vb index fb6bb5b46f69e..5b1531fea24fc 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ForLoopBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/ForLoopBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class ForLoopBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MethodDeclarationHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MethodDeclarationHighlighterTests.vb index b58873fbff46c..ec876030783a8 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MethodDeclarationHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MethodDeclarationHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class MethodDeclarationHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MultiLineIfBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MultiLineIfBlockHighlighterTests.vb index 139ecac7adc33..7da3e5b10f131 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MultiLineIfBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MultiLineIfBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class MultiLineIfBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MultiLineLambdaExpressionHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MultiLineLambdaExpressionHighlighterTests.vb index b98036c517166..ea8541bbd69f9 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MultiLineLambdaExpressionHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/MultiLineLambdaExpressionHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class MultiLineLambdaExpressionHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/NamespaceBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/NamespaceBlockHighlighterTests.vb index bdd6e4565e471..b931d459b9a40 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/NamespaceBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/NamespaceBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class NamespaceBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/OperatorDeclarationHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/OperatorDeclarationHighlighterTests.vb index 5f3c8c7a8d68a..b10a633786486 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/OperatorDeclarationHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/OperatorDeclarationHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class OperatorDeclarationHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/PropertyDeclarationHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/PropertyDeclarationHighlighterTests.vb index f20d232aa7257..1a18525da4c9f 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/PropertyDeclarationHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/PropertyDeclarationHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class PropertyDeclarationHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/RegionHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/RegionHighlighterTests.vb index b906018cfa316..4e95a3d98bf1c 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/RegionHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/RegionHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class RegionHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SelectBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SelectBlockHighlighterTests.vb index a1ffd4223a8bb..a69fe46320a90 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SelectBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SelectBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class SelectBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SingleLineIfBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SingleLineIfBlockHighlighterTests.vb index 9e1d8515baee4..77af0be65a8bb 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SingleLineIfBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SingleLineIfBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class SingleLineIfBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SyncLockBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SyncLockBlockHighlighterTests.vb index e66ab2b7a39fb..ed4deb09dd96c 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SyncLockBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/SyncLockBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class SyncLockBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/TryBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/TryBlockHighlighterTests.vb index 3f93ae32e3454..b79af72106281 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/TryBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/TryBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class TryBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/TypeBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/TypeBlockHighlighterTests.vb index 61138c9c64931..3e0e4d637cf18 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/TypeBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/TypeBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class TypeBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/UsingBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/UsingBlockHighlighterTests.vb index 7fd19d4e70acc..d8ccd1faa82d8 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/UsingBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/UsingBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class UsingBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/WhileBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/WhileBlockHighlighterTests.vb index 79dd8aab617d1..da4db3b12624f 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/WhileBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/WhileBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class WhileBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/WithBlockHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/WithBlockHighlighterTests.vb index 36049b9ce91d0..64a73c07cd046 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/WithBlockHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/WithBlockHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class WithBlockHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlCDataHighligherTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlCDataHighligherTests.vb index 653dd595f28e0..f92a007ed020f 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlCDataHighligherTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlCDataHighligherTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class XmlCDataHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlCommentHighligherTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlCommentHighligherTests.vb index 9d3d7bc5a1cb6..f64a6bfdc32da 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlCommentHighligherTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlCommentHighligherTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class XmlCommentHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlDocumentPrologueHighligherTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlDocumentPrologueHighligherTests.vb index 698d26b80f4f8..9a4fe44e62b95 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlDocumentPrologueHighligherTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlDocumentPrologueHighligherTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class XmlDocumentPrologueHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlElementHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlElementHighlighterTests.vb index 76482619d8596..7ba658262b3cb 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlElementHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlElementHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class XmlElementHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlEmbeddedExpressionHighligherTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlEmbeddedExpressionHighligherTests.vb index 819e855b80cdc..bd59ef674fc6a 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlEmbeddedExpressionHighligherTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlEmbeddedExpressionHighligherTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class XmlEmbeddedExpressionHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlProcessingInstructionHighlighterTests.vb b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlProcessingInstructionHighlighterTests.vb index 030d5fad28632..0b60e5c3a20b1 100644 --- a/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlProcessingInstructionHighlighterTests.vb +++ b/src/EditorFeatures/VisualBasicTest/KeywordHighlighting/XmlProcessingInstructionHighlighterTests.vb @@ -2,7 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Imports Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.KeywordHighlighting Public Class XmlProcessingInstructionHighlighterTests diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb index d731c2adaca28..84195145ab748 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb @@ -9,8 +9,8 @@ Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Editor.VisualBasic.LineCommit -Imports Microsoft.CodeAnalysis.Indentation Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.Rename Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.Text.Shared.Extensions Imports Microsoft.VisualStudio.Text @@ -98,7 +98,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit End Get End Property - Public Function StartInlineSession(snapshot As Document, triggerSpan As TextSpan, Optional cancellationToken As CancellationToken = Nothing) As InlineRenameSessionInfo Implements IInlineRenameService.StartInlineSession + Public Function StartInlineSession(snapshot As Document, triggerSpan As TextSpan, cancellationToken As CancellationToken) As InlineRenameSessionInfo Implements IInlineRenameService.StartInlineSession Throw New NotImplementedException() End Function diff --git a/src/EditorFeatures/VisualBasicTest/LineSeparators/LineSeparatorTests.vb b/src/EditorFeatures/VisualBasicTest/LineSeparators/LineSeparatorTests.vb index 871551b8b7031..1eb452f9432b2 100644 --- a/src/EditorFeatures/VisualBasicTest/LineSeparators/LineSeparatorTests.vb +++ b/src/EditorFeatures/VisualBasicTest/LineSeparators/LineSeparatorTests.vb @@ -6,6 +6,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Editor.VisualBasic.LineSeparators +Imports Microsoft.CodeAnalysis.LineSeparators Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.Text @@ -290,7 +291,7 @@ End Class") Dim document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id) Dim service = Assert.IsType(Of VisualBasicLineSeparatorService)(workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetService(Of ILineSeparatorService)()) Dim spans = Await service.GetLineSeparatorsAsync(document, - (Await document.GetSyntaxRootAsync()).FullSpan) + (Await document.GetSyntaxRootAsync()).FullSpan, Nothing) Return spans.OrderBy(Function(span) span.Start) End Using End Function diff --git a/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb b/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb index 820341176ecdc..170b0a9fb8182 100644 --- a/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb +++ b/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb @@ -1050,6 +1050,21 @@ End Class Await _aggregator.GetItemsAsync("Outer")) End Using End Function + + + + Public Async Function FindMethodWithTuple(testHost As TestHost, composition As Composition) As Task + Await TestAsync(testHost, composition, "Class Goo + Public Sub Method( + t1 as (x as integer, y as Dictionary(of integer, string)), + t2 as (b as boolean, c as global.System.Int32) ) + End Sub +End Class", Async Function(w) + Dim item As NavigateToItem = (Await _aggregator.GetItemsAsync("Method")).Single() + VerifyNavigateToResultItem(item, "Method", "[|Method|]((x as integer, y as Dictionary(of integer, string)), (b as boolean, c as global.System.Int32))", PatternMatchKind.Exact, NavigateToItemKind.Method, + Glyph.MethodPublic, String.Format(FeaturesResources.in_0_project_1, "Goo", "Test")) + End Function) + End Function End Class End Namespace #Enable Warning BC40000 ' MatchKind is obsolete diff --git a/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb b/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb index 18a360f2ec676..0dde90b1f69e1 100644 --- a/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb @@ -7,6 +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.QuickInfo Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.QuickInfo @@ -40,7 +41,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.QuickInfo Private Shared Async Function TestSharedAsync(workspace As TestWorkspace, service As QuickInfoService, position As Integer, expectedResults() As Action(Of QuickInfoItem)) As Task Dim info = Await service.GetQuickInfoAsync( workspace.CurrentSolution.Projects.First().Documents.First(), - position, cancellationToken:=CancellationToken.None) + position, SymbolDescriptionOptions.Default, CancellationToken.None) If expectedResults Is Nothing Then Assert.Null(info) @@ -950,7 +951,8 @@ Module Program End Sub End Module ]]>.NormalizedValue, - MainDescription($"({FeaturesResources.local_variable}) a As ")) + MainDescription($"({FeaturesResources.local_variable}) a As 'a"), + AnonymousTypes(vbCrLf & FeaturesResources.Types_colon & vbCrLf & $" 'a {FeaturesResources.is_} Delegate Sub ()")) End Function @@ -966,7 +968,8 @@ Module Program End Sub End Module ]]>.NormalizedValue, - MainDescription($"({FeaturesResources.local_variable}) a As ")) + MainDescription($"({FeaturesResources.local_variable}) a As 'a"), + AnonymousTypes(vbCrLf & FeaturesResources.Types_colon & vbCrLf & $" 'a {FeaturesResources.is_} Delegate Function () As Integer")) End Function @@ -981,9 +984,10 @@ Module Program End Sub End Module ]]>.NormalizedValue, - MainDescription($"({FeaturesResources.local_variable}) a As "), + MainDescription($"({FeaturesResources.local_variable}) a As 'a"), AnonymousTypes(vbCrLf & FeaturesResources.Types_colon & vbCrLf & - $" 'a {FeaturesResources.is_} New With {{ .Goo As String }}")) + $" 'a {FeaturesResources.is_} Delegate Function () As 'b" & vbCrLf & + $" 'b {FeaturesResources.is_} New With {{ .Goo As String }}")) End Function @@ -999,9 +1003,11 @@ Module Program End Sub End Module ]]>.NormalizedValue, - MainDescription($"({FeaturesResources.local_variable}) a As "), + MainDescription($"({FeaturesResources.local_variable}) a As 'a"), AnonymousTypes(vbCrLf & FeaturesResources.Types_colon & vbCrLf & - $" 'a {FeaturesResources.is_} New With {{ .Sq As Integer, .M As }}")) + $" 'a {FeaturesResources.is_} Delegate Function (i As Integer) As 'b" & vbCrLf & + $" 'b {FeaturesResources.is_} New With {{ .Sq As Integer, .M As 'c }}" & vbCrLf & + $" 'c {FeaturesResources.is_} Delegate Function (j As Integer) As Integer")) End Function diff --git a/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb b/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb index 82ff01038ae49..71869c016604f 100644 --- a/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb @@ -18,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Wrapping Private Protected Function GetIndentionColumn(column As Integer) As OptionsCollection Return New OptionsCollection(GetLanguage()) From { - {FormattingBehaviorOptions.PreferredWrappingColumn, column} + {FormattingOptions2.PreferredWrappingColumn, column} } End Function diff --git a/src/EditorFeatures/VisualBasicTest/Wrapping/InitializerExpressionWrappingTests.vb b/src/EditorFeatures/VisualBasicTest/Wrapping/InitializerExpressionWrappingTests.vb new file mode 100644 index 0000000000000..96d383340a085 --- /dev/null +++ b/src/EditorFeatures/VisualBasicTest/Wrapping/InitializerExpressionWrappingTests.vb @@ -0,0 +1,431 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports Microsoft.CodeAnalysis.CodeRefactorings +Imports Microsoft.CodeAnalysis.VisualBasic.Wrapping + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Wrapping + Public Class InitializerExpressionWrappingTests + Inherits AbstractWrappingTests + + Protected Overrides Function CreateCodeRefactoringProvider(workspace As Workspace, parameters As TestParameters) As CodeRefactoringProvider + Return New VisualBasicWrappingCodeRefactoringProvider() + End Function + + + Public Async Function TestNoWrappingSuggestions() As Task + Await TestMissingAsync( +"Class C + Public Sub Bar() + Dim test() As Integer = New Integer() [||]{1} + End Sub +End Class") + End Function + + + Public Async Function TestWrappingShortInitializerExpression() As Task + Await TestAllWrappingCasesAsync( +"Class C + Public Sub Bar() + Dim test() As Integer = New Integer() [||]{1, 2} + End Sub +End Class", +"Class C + Public Sub Bar() + Dim test() As Integer = New Integer() { + 1, + 2 + } + End Sub +End Class", "Class C + Public Sub Bar() + Dim test() As Integer = New Integer() { + 1, 2 + } + End Sub +End Class") + End Function + + + Public Async Function TestWrappingLongIntializerExpression() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Dim test() As String = New String() [||]{""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog""} + End Sub +}", "Class C + Public Sub Bar() + Dim test() As String = New String() { + ""the"", + ""quick"", + ""brown"", + ""fox"", + ""jumps"", + ""over"", + ""the"", + ""lazy"", + ""dog"" + } + End Sub +}", "Class C + Public Sub Bar() + Dim test() As String = New String() { + ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"" + } + End Sub +}") + End Function + + + Public Async Function TestWrappingMultiLineLongIntializerExpression() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Dim test() As String = New String() [||]{""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"", ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog""} + End Sub +}", "Class C + Public Sub Bar() + Dim test() As String = New String() { + ""the"", + ""quick"", + ""brown"", + ""fox"", + ""jumps"", + ""over"", + ""the"", + ""lazy"", + ""dog"", + ""the"", + ""quick"", + ""brown"", + ""fox"", + ""jumps"", + ""over"", + ""the"", + ""lazy"", + ""dog"" + } + End Sub +}", "Class C + Public Sub Bar() + Dim test() As String = New String() { + ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"", ""the"", ""quick"", ""brown"", ""fox"", + ""jumps"", ""over"", ""the"", ""lazy"", ""dog"" + } + End Sub +}") + End Function + + + Public Async Function TestShortInitializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Dim test() As Integer = New Integer() [||]{ + 1, + 2 + } + End Sub +End Class", "Class C + Public Sub Bar() + Dim test() As Integer = New Integer() {1, 2} + End Sub +End Class", "Class C + Public Sub Bar() + Dim test() As Integer = New Integer() { + 1, 2 + } + End Sub +End Class") + End Function + + + Public Async Function TestLongIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Dim test() As String = New String() [||]{ + ""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog"" + } + End Sub +End Class", "Class C + Public Sub Bar() + Dim test() As String = New String() { + ""the"", + ""quick"", + ""brown"", + ""fox"", + ""jumps"", + ""over"", + ""the"", + ""lazy"", + ""dog"" + } + End Sub +End Class", "Class C + Public Sub Bar() + Dim test() As String = New String() {""the"", ""quick"", ""brown"", ""fox"", ""jumps"", ""over"", ""the"", ""lazy"", ""dog""} + End Sub +End Class") + End Function + + + Public Async Function TestListIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Dim test As New List(Of Integer) From [||]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + End Sub +End Class", "Class C + Public Sub Bar() + Dim test As New List(Of Integer) From { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + } + End Sub +End Class", "Class C + Public Sub Bar() + Dim test As New List(Of Integer) From { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + } + End Sub +End Class") + End Function + + + Public Async Function TestWrappedListIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Dim test As New List(Of Integer) From [||]{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + } + End Sub +End Class", "Class C + Public Sub Bar() + Dim test As New List(Of Integer) From {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + End Sub +End Class", "Class C + Public Sub Bar() + Dim test As New List(Of Integer) From { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + } + End Sub +End Class") + End Function + + + Public Async Function TestObjectIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Dim test As New List(Of A) From [||]{New A() With {.B = 0, .C = 1}, New A() With {.B = 0, .C = 1}, New A() With {.B = 0, .C = 1}} + End Sub +End Class", "Class C + Public Sub Bar() + Dim test As New List(Of A) From { + New A() With {.B = 0, .C = 1}, + New A() With {.B = 0, .C = 1}, + New A() With {.B = 0, .C = 1} + } + End Sub +End Class", "Class C + Public Sub Bar() + Dim test As New List(Of A) From { + New A() With {.B = 0, .C = 1}, New A() With {.B = 0, .C = 1}, New A() With {.B = 0, .C = 1} + } + End Sub +End Class") + End Function + + + Public Async Function TestWrappedObjectIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Dim test As New List(Of A) From [||]{ + New A() With {.B = 0, .C = 1}, + New A() With {.B = 0, .C = 1}, + New A() With {.B = 0, .C = 1} + } + End Sub +End Class", "Class C + Public Sub Bar() + Dim test As New List(Of A) From {New A() With {.B = 0, .C = 1}, New A() With {.B = 0, .C = 1}, New A() With {.B = 0, .C = 1}} + End Sub +End Class", "Class C + Public Sub Bar() + Dim test As New List(Of A) From { + New A() With {.B = 0, .C = 1}, New A() With {.B = 0, .C = 1}, New A() With {.B = 0, .C = 1} + } + End Sub +End Class") + End Function + + + Public Async Function TestReturnIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Return New List(Of Integer) From [||]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + End Sub +End Class", "Class C + Public Sub Bar() + Return New List(Of Integer) From { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + } + End Sub +End Class", "Class C + Public Sub Bar() + Return New List(Of Integer) From { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + } + End Sub +End Class") + End Function + + + Public Async Function TestWrappedReturnIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Class C + Public Sub Bar() + Return New List(Of Integer) From [||]{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + } + End Sub +End Class", "Class C + Public Sub Bar() + Return New List(Of Integer) From {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + End Sub +End Class", "Class C + Public Sub Bar() + Return New List(Of Integer) From { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + } + End Sub +End Class") + End Function + + + Public Async Function TestClassPropertyIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Public Class C + Public Property B As New List(Of Integer) From [||]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} +End Class", "Public Class C + Public Property B As New List(Of Integer) From { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + } +End Class", "Public Class C + Public Property B As New List(Of Integer) From { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + } +End Class") + End Function + + + Public Async Function TestWrappedClassPropertyIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Public Class C + Public Property B As New List(Of Integer) From [||]{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + } +End Class", "Public Class C + Public Property B As New List(Of Integer) From {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} +End Class", "Public Class C + Public Property B As New List(Of Integer) From { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + } +End Class") + End Function + + + Public Async Function TestArgumentIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Public Sub F + Dim result = FakeFunction(New List(Of Integer) From [||]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) +End Sub", "Public Sub F + Dim result = FakeFunction(New List(Of Integer) From { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }) +End Sub", "Public Sub F + Dim result = FakeFunction(New List(Of Integer) From { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }) +End Sub") + End Function + + + Public Async Function TestWrappedArgumentIntializerExpressionRefactorings() As Task + Await TestAllWrappingCasesAsync("Public Sub F + Dim result = FakeFunction(New List(Of Integer) From [||]{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + }) +End Sub", "Public Sub F + Dim result = FakeFunction(New List(Of Integer) From {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) +End Sub", "Public Sub F + Dim result = FakeFunction(New List(Of Integer) From { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }) +End Sub") + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/Wrapping/ParameterWrappingTests.vb b/src/EditorFeatures/VisualBasicTest/Wrapping/ParameterWrappingTests.vb index d82120db9ab6b..1077a396d550b 100644 --- a/src/EditorFeatures/VisualBasicTest/Wrapping/ParameterWrappingTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Wrapping/ParameterWrappingTests.vb @@ -22,6 +22,20 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Wrapping end class") End Function + + Public Async Function TestAvailableWithSyntaxErrorAfter() As Task + Await TestInRegularAndScript1Async( +"class C + function Goobar([||]i as integer, j as integer) as + end function +end class", +"class C + function Goobar(i as integer, + j as integer) as + end function +end class") + End Function + Public Async Function TestMissingWithSelection() As Task Await TestMissingAsync( diff --git a/src/ExpressionEvaluator/CSharp/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.CSharp.ResultProvider.csproj b/src/ExpressionEvaluator/CSharp/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.CSharp.ResultProvider.csproj index 230395a943404..b984824f83ed2 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.CSharp.ResultProvider.csproj +++ b/src/ExpressionEvaluator/CSharp/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.CSharp.ResultProvider.csproj @@ -5,8 +5,7 @@ Library Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.ResultProvider - - netstandard1.3 + netstandard2.0 full diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs index aac4c63c0c555..deba1106a7a49 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs @@ -1742,7 +1742,7 @@ static void M1() static void M2() { } static void M2(int i) { } }"; - var compilation0 = CreateCompilation(source, options: TestOptions.DebugDll); + var compilation0 = CreateCompilation(source, parseOptions: TestOptions.Regular10, options: TestOptions.DebugDll); WithRuntimeInstance(compilation0, runtime => { var context = CreateMethodContext( @@ -1756,7 +1756,12 @@ static void M2(int i) { } error: out error, testData: testData); Assert.Equal("error CS8917: The delegate type could not be inferred.", error); + testData = new CompilationTestData(); + + // If you see this failing, please fix https://github.com/dotnet/roslyn/issues/58449 + Assert.Equal(compilation0.LanguageVersion, context.Compilation.LanguageVersion); + context.CompileAssignment( target: "o", expr: "M1", @@ -4170,13 +4175,20 @@ static void M() { } }"; - var testData = Evaluate( - source, - OutputKind.DynamicallyLinkedLibrary, - methodName: "C.M", - expr: "G(F)"); - testData.GetMethodData("<>x.<>m0").VerifyIL( -@"{ + var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular10, options: TestOptions.DebugDll); + WithRuntimeInstance(compilation, runtime => + { + var context = CreateMethodContext( + runtime, + methodName: "C.M"); + var testData = new CompilationTestData(); + var result = context.CompileExpression("G(F)", out var error, testData); + + // If you see this failing, please fix https://github.com/dotnet/roslyn/issues/58449 + Assert.Equal(compilation.LanguageVersion, context.Compilation.LanguageVersion); + + testData.GetMethodData("<>x.<>m0").VerifyIL(@" +{ // Code size 18 (0x12) .maxstack 2 IL_0000: ldnull @@ -4184,7 +4196,9 @@ .maxstack 2 IL_0007: newobj ""D..ctor(object, System.IntPtr)"" IL_000c: call ""void C.G(D)"" IL_0011: ret -}"); +} +"); + }); } [Fact] diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/EvaluationContextBase.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/EvaluationContextBase.cs index 1cc44cc80d3c2..21d5d4904f976 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/EvaluationContextBase.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/EvaluationContextBase.cs @@ -153,11 +153,6 @@ public override bool Equals(Diagnostic? obj) throw new NotImplementedException(); } - public override bool Equals(object? obj) - { - throw new NotImplementedException(); - } - public override int GetHashCode() { throw new NotImplementedException(); diff --git a/src/ExpressionEvaluator/Core/Source/FunctionResolver/Microsoft.CodeAnalysis.FunctionResolver.csproj b/src/ExpressionEvaluator/Core/Source/FunctionResolver/Microsoft.CodeAnalysis.FunctionResolver.csproj index 72d0cac354d38..e1f9cf121dabc 100644 --- a/src/ExpressionEvaluator/Core/Source/FunctionResolver/Microsoft.CodeAnalysis.FunctionResolver.csproj +++ b/src/ExpressionEvaluator/Core/Source/FunctionResolver/Microsoft.CodeAnalysis.FunctionResolver.csproj @@ -6,8 +6,7 @@ Microsoft.CodeAnalysis.ExpressionEvaluator Microsoft.CodeAnalysis.ExpressionEvaluator.FunctionResolver true - - net45;netstandard1.3 + net45;netstandard2.0 diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/ArrayExpansion.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/ArrayExpansion.cs index de7e286615205..7aefc7364810f 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/ArrayExpansion.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/ArrayExpansion.cs @@ -105,7 +105,11 @@ private int[] GetIndices(int index) { if (_divisors == null) { - return new[] { index }; + // _divisors is null if dimension is 1, but + // _lowerBounds need not necessarily be so. + Debug.Assert(_lowerBounds == null || _lowerBounds.Count == 1); + int lowerBound = _lowerBounds != null && _lowerBounds.Count == 1 ? _lowerBounds[0] : 0; + return new[] { lowerBound + index }; } var n = _divisors.Count; diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.ResultProvider.csproj b/src/ExpressionEvaluator/Core/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.ResultProvider.csproj index 12de7084e861c..740281bca5615 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.ResultProvider.csproj +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.ResultProvider.csproj @@ -5,8 +5,7 @@ Library Microsoft.CodeAnalysis.ExpressionEvaluator Microsoft.CodeAnalysis.ExpressionEvaluator.ResultProvider - - netstandard1.3 + netstandard2.0 full @@ -78,6 +77,7 @@ + \ No newline at end of file diff --git a/src/ExpressionEvaluator/Package/ExpressionEvaluatorPackage.csproj b/src/ExpressionEvaluator/Package/ExpressionEvaluatorPackage.csproj index fb28bdb6c0f7e..457732308ebdc 100644 --- a/src/ExpressionEvaluator/Package/ExpressionEvaluatorPackage.csproj +++ b/src/ExpressionEvaluator/Package/ExpressionEvaluatorPackage.csproj @@ -35,7 +35,7 @@ BuiltProjectOutputGroup%3bVsdConfigOutputGroup;SatelliteDllsProjectOutputGroup DebugSymbolsProjectOutputGroup true - TargetFramework=netstandard1.3 + TargetFramework=netstandard2.0 BindingRedirect diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.VisualBasic.ResultProvider.vbproj b/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.VisualBasic.ResultProvider.vbproj index 6e5c1b8f8cba3..459fd83d79d62 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.VisualBasic.ResultProvider.vbproj +++ b/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/Portable/Microsoft.CodeAnalysis.VisualBasic.ResultProvider.vbproj @@ -4,8 +4,7 @@ Library Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.ResultProvider - - netstandard1.3 + netstandard2.0 diff --git a/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs index 38875bc12b7ed..e7a01ce10b8f1 100644 --- a/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/AddDebuggerDisplay/CSharpAddDebuggerDisplayCodeRefactoringProvider.cs @@ -6,6 +6,7 @@ using System.Composition; using Microsoft.CodeAnalysis.AddDebuggerDisplay; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; @@ -27,6 +28,6 @@ public CSharpAddDebuggerDisplayCodeRefactoringProvider() protected override bool CanNameofAccessNonPublicMembersFromAttributeArgument => true; protected override bool SupportsConstantInterpolatedStrings(Document document) - => ((CSharpParseOptions)document.Project.ParseOptions!).LanguageVersion.HasConstantInterpolatedStrings(); + => document.Project.ParseOptions!.LanguageVersion().HasConstantInterpolatedStrings(); } } diff --git a/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs b/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs index 4809db6993b38..d683b1726eb6e 100644 --- a/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs +++ b/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs @@ -13,7 +13,8 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; @@ -288,7 +289,7 @@ protected override string GetDescription(IReadOnlyList nameParts) protected override (string description, bool hasExistingImport) GetDescription( Document document, - OptionSet options, + AddImportPlacementOptions options, INamespaceOrTypeSymbol namespaceOrTypeSymbol, SemanticModel semanticModel, SyntaxNode contextNode, @@ -340,19 +341,18 @@ protected override async Task AddImportAsync( SyntaxNode contextNode, INamespaceOrTypeSymbol namespaceOrTypeSymbol, Document document, - bool allowInHiddenRegions, + AddImportPlacementOptions options, CancellationToken cancellationToken) { var root = GetCompilationUnitSyntaxNode(contextNode, cancellationToken); - var newRoot = await AddImportWorkerAsync(document, root, contextNode, namespaceOrTypeSymbol, allowInHiddenRegions, cancellationToken).ConfigureAwait(false); + var newRoot = await AddImportWorkerAsync(document, root, contextNode, namespaceOrTypeSymbol, options, cancellationToken).ConfigureAwait(false); return document.WithSyntaxRoot(newRoot); } private async Task AddImportWorkerAsync( Document document, CompilationUnitSyntax root, SyntaxNode contextNode, INamespaceOrTypeSymbol namespaceOrTypeSymbol, - bool allowInHiddenRegions, CancellationToken cancellationToken) + AddImportPlacementOptions options, CancellationToken cancellationToken) { - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var (externAliasDirective, hasExistingExtern) = GetExternAliasDirective( @@ -381,15 +381,14 @@ private async Task AddImportWorkerAsync( var addImportService = document.GetLanguageService(); var generator = SyntaxGenerator.GetGenerator(document); var newRoot = addImportService.AddImports( - semanticModel.Compilation, root, contextNode, newImports, generator, options, allowInHiddenRegions, cancellationToken); + semanticModel.Compilation, root, contextNode, newImports, generator, options, cancellationToken); return (CompilationUnitSyntax)newRoot; } protected override async Task AddImportAsync( SyntaxNode contextNode, IReadOnlyList namespaceParts, - Document document, bool allowInHiddenRegions, CancellationToken cancellationToken) + Document document, AddImportPlacementOptions options, CancellationToken cancellationToken) { - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var root = GetCompilationUnitSyntaxNode(contextNode, cancellationToken); var usingDirective = SyntaxFactory.UsingDirective( @@ -399,7 +398,7 @@ protected override async Task AddImportAsync( var service = document.GetLanguageService(); var generator = SyntaxGenerator.GetGenerator(document); var newRoot = service.AddImport( - compilation, root, contextNode, usingDirective, generator, options, allowInHiddenRegions, cancellationToken); + compilation, root, contextNode, usingDirective, generator, options, cancellationToken); return document.WithSyntaxRoot(newRoot); } @@ -436,7 +435,7 @@ private static (ExternAliasDirectiveSyntax, bool hasExistingImport) GetExternAli private (UsingDirectiveSyntax, bool hasExistingImport) GetUsingDirective( Document document, - OptionSet options, + AddImportPlacementOptions options, INamespaceOrTypeSymbol namespaceOrTypeSymbol, SemanticModel semanticModel, CompilationUnitSyntax root, diff --git a/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs index c4f71d2592a47..7939374ab92c5 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs @@ -49,23 +49,26 @@ public CurlyBraceCompletionService() public override Task AllowOverTypeAsync(BraceCompletionContext context, CancellationToken cancellationToken) => AllowOverTypeInUserCodeWithValidClosingTokenAsync(context, cancellationToken); - public override async Task GetTextChangesAfterCompletionAsync(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken) + public override async Task GetTextChangesAfterCompletionAsync(BraceCompletionContext context, IndentationOptions options, CancellationToken cancellationToken) { - var documentOptions = await braceCompletionContext.Document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - // 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 // if (true){$$} // We then need to format this to // if (true) { $$} + + if (!options.AutoFormattingOptions.FormatOnCloseBrace) + { + return null; + } + var (formattingChanges, finalCurlyBraceEnd) = await FormatTrackingSpanAsync( - braceCompletionContext.Document, - braceCompletionContext.OpeningPoint, - braceCompletionContext.ClosingPoint, - shouldHonorAutoFormattingOnCloseBraceOption: true, + context.Document, + context.OpeningPoint, + context.ClosingPoint, // We're not trying to format the indented block here, so no need to pass in additional rules. braceFormattingIndentationRules: ImmutableArray.Empty, - documentOptions, + options, cancellationToken).ConfigureAwait(false); if (formattingChanges.IsEmpty) @@ -74,7 +77,7 @@ public override Task AllowOverTypeAsync(BraceCompletionContext context, Ca } // The caret location should be at the start of the closing brace character. - var originalText = await braceCompletionContext.Document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var originalText = await context.Document.GetTextAsync(cancellationToken).ConfigureAwait(false); var formattedText = originalText.WithChanges(formattingChanges); var caretLocation = formattedText.Lines.GetLinePosition(finalCurlyBraceEnd - 1); @@ -83,7 +86,7 @@ public override Task AllowOverTypeAsync(BraceCompletionContext context, Ca public override async Task GetTextChangeAfterReturnAsync( BraceCompletionContext context, - DocumentOptionSet documentOptions, + IndentationOptions options, CancellationToken cancellationToken) { var document = context.Document; @@ -113,7 +116,7 @@ public override Task AllowOverTypeAsync(BraceCompletionContext context, Ca var textToFormat = originalDocumentText; if (closingPointLine - openingPointLine == 1) { - var newLineString = documentOptions.GetOption(FormattingOptions2.NewLine); + var newLineString = options.FormattingOptions.NewLine; newLineEdit = new TextChange(new TextSpan(closingPoint - 1, 0), newLineString); textToFormat = originalDocumentText.WithChanges(newLineEdit.Value); @@ -121,15 +124,18 @@ public override Task AllowOverTypeAsync(BraceCompletionContext context, Ca closingPoint += newLineString.Length; } + var braceFormattingIndentationRules = ImmutableArray.Create( + BraceCompletionFormattingRule.ForIndentStyle(options.AutoFormattingOptions.IndentStyle)); + // Format the text that contains the newly inserted line. var (formattingChanges, newClosingPoint) = await FormatTrackingSpanAsync( document.WithText(textToFormat), openingPoint, closingPoint, - shouldHonorAutoFormattingOnCloseBraceOption: false, - braceFormattingIndentationRules: GetBraceIndentationFormattingRules(documentOptions), - documentOptions, + braceFormattingIndentationRules, + options, cancellationToken).ConfigureAwait(false); + closingPoint = newClosingPoint; var formattedText = textToFormat.WithChanges(formattingChanges); @@ -237,17 +243,10 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, Document document, int openingPoint, int closingPoint, - bool shouldHonorAutoFormattingOnCloseBraceOption, ImmutableArray braceFormattingIndentationRules, - DocumentOptionSet documentOptions, + IndentationOptions options, CancellationToken cancellationToken) { - var option = document.Project.Solution.Options.GetOption(BraceCompletionOptions.AutoFormattingOnCloseBrace, document.Project.Language); - if (!option && shouldHonorAutoFormattingOnCloseBraceOption) - { - return (ImmutableArray.Empty, closingPoint); - } - // Annotate the original closing brace so we can find it after formatting. document = await GetDocumentWithAnnotatedClosingBraceAsync(document, closingPoint, cancellationToken).ConfigureAwait(false); @@ -275,8 +274,7 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, } } - var style = documentOptions.GetOption(FormattingOptions.SmartIndent); - if (style == FormattingOptions.IndentStyle.Smart) + if (options.AutoFormattingOptions.IndentStyle == FormattingOptions.IndentStyle.Smart) { // Set the formatting start point to be the beginning of the first word to the left // of the opening brace location. @@ -296,8 +294,9 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, var spanToFormat = TextSpan.FromBounds(Math.Max(startPoint, 0), endPoint); var rules = document.GetFormattingRules(spanToFormat, braceFormattingIndentationRules); + var services = document.Project.Solution.Workspace.Services; var result = Formatter.GetFormattingResult( - root, SpecializedCollections.SingletonEnumerable(spanToFormat), document.Project.Solution.Workspace, documentOptions, rules, cancellationToken); + root, SpecializedCollections.SingletonEnumerable(spanToFormat), services, options.FormattingOptions, rules, cancellationToken); if (result == null) { return (ImmutableArray.Empty, closingPoint); @@ -321,12 +320,6 @@ static async Task GetDocumentWithAnnotatedClosingBraceAsync(Document d } } - private static ImmutableArray GetBraceIndentationFormattingRules(DocumentOptionSet documentOptions) - { - var indentStyle = documentOptions.GetOption(FormattingOptions.SmartIndent); - return ImmutableArray.Create(BraceCompletionFormattingRule.ForIndentStyle(indentStyle)); - } - private sealed class BraceCompletionFormattingRule : BaseFormattingRule { private static readonly Predicate s_predicate = o => o == null || o.Option.IsOn(SuppressOption.NoWrapping); @@ -337,14 +330,14 @@ private sealed class BraceCompletionFormattingRule : BaseFormattingRule new BraceCompletionFormattingRule(FormattingOptions.IndentStyle.Smart)); private readonly FormattingOptions.IndentStyle _indentStyle; - private readonly CachedOptions _options; + private readonly CSharpSyntaxFormattingOptions _options; public BraceCompletionFormattingRule(FormattingOptions.IndentStyle indentStyle) - : this(indentStyle, new CachedOptions(null)) + : this(indentStyle, CSharpSyntaxFormattingOptions.Default) { } - private BraceCompletionFormattingRule(FormattingOptions.IndentStyle indentStyle, CachedOptions options) + private BraceCompletionFormattingRule(FormattingOptions.IndentStyle indentStyle, CSharpSyntaxFormattingOptions options) { _indentStyle = indentStyle; _options = options; @@ -356,20 +349,24 @@ public static AbstractFormattingRule ForIndentStyle(FormattingOptions.IndentStyl return s_instances[(int)indentStyle]; } - public override AbstractFormattingRule WithOptions(AnalyzerConfigOptions options) + public override AbstractFormattingRule WithOptions(SyntaxFormattingOptions options) { - var cachedOptions = new CachedOptions(options); - - if (cachedOptions == _options) + var newOptions = options as CSharpSyntaxFormattingOptions ?? CSharpSyntaxFormattingOptions.Default; + if (_options.NewLines == newOptions.NewLines) { return this; } - return new BraceCompletionFormattingRule(_indentStyle, cachedOptions); + return new BraceCompletionFormattingRule(_indentStyle, newOptions); } - public override AdjustNewLinesOperation? GetAdjustNewLinesOperation(in SyntaxToken previousToken, in SyntaxToken currentToken, in NextGetAdjustNewLinesOperation nextOperation) + private static bool? NeedsNewLine(in SyntaxToken currentToken, CSharpSyntaxFormattingOptions options) { + if (!currentToken.IsKind(SyntaxKind.OpenBraceToken)) + { + return null; + } + // If we're inside any of the following expressions check if the option for // braces on new lines in object / array initializers is set before we attempt // to move the open brace location to a new line. @@ -378,23 +375,109 @@ public override AbstractFormattingRule WithOptions(AnalyzerConfigOptions options // int[] arr = { // = new[] { // = new int[] { - if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentToken.Parent.IsKind( + if (currentToken.Parent.IsKind( SyntaxKind.ObjectInitializerExpression, SyntaxKind.CollectionInitializerExpression, SyntaxKind.ArrayInitializerExpression, - SyntaxKind.ImplicitArrayCreationExpression)) + SyntaxKind.ImplicitArrayCreationExpression, + SyntaxKind.WithInitializerExpression, + SyntaxKind.PropertyPatternClause)) { - if (_options.NewLinesForBracesInObjectCollectionArrayInitializers) - { - return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines); - } - else - { - return null; - } + return options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers); + } + + var currentTokenParentParent = currentToken.Parent?.Parent; + + // * { - in the property accessor context + if (currentTokenParentParent is AccessorDeclarationSyntax) + { + return options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInAccessors); + } + + // * { - in the anonymous Method context + if (currentTokenParentParent.IsKind(SyntaxKind.AnonymousMethodExpression)) + { + return options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInAnonymousMethods); + } + + // new { - Anonymous object creation + if (currentToken.Parent.IsKind(SyntaxKind.AnonymousObjectCreationExpression)) + { + return options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInAnonymousTypes); + } + + // * { - in the control statement context + if (IsControlBlock(currentToken.Parent)) + { + return options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInControlBlocks); + } + + // * { - in the simple Lambda context + if (currentTokenParentParent.IsKind(SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression)) + { + return options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInLambdaExpressionBody); } - return base.GetAdjustNewLinesOperation(in previousToken, in currentToken, in nextOperation); + // * { - in the member declaration context + if (currentTokenParentParent is MemberDeclarationSyntax) + { + return currentTokenParentParent is BasePropertyDeclarationSyntax + ? options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInProperties) + : options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInMethods); + } + + // * { - in the type declaration context + if (currentToken.Parent is BaseTypeDeclarationSyntax or NamespaceDeclarationSyntax) + { + return options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInTypes); + } + + return null; + } + + private static bool IsControlBlock(SyntaxNode? node) + { + if (node.IsKind(SyntaxKind.SwitchStatement)) + { + return true; + } + + var parentKind = node?.Parent?.Kind(); + + switch (parentKind.GetValueOrDefault()) + { + case SyntaxKind.IfStatement: + case SyntaxKind.ElseClause: + case SyntaxKind.WhileStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.ForEachStatement: + case SyntaxKind.ForEachVariableStatement: + case SyntaxKind.UsingStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.CatchClause: + case SyntaxKind.FinallyClause: + case SyntaxKind.LockStatement: + case SyntaxKind.CheckedStatement: + case SyntaxKind.UncheckedStatement: + case SyntaxKind.SwitchSection: + case SyntaxKind.FixedStatement: + case SyntaxKind.UnsafeStatement: + return true; + default: + return false; + } + } + + public override AdjustNewLinesOperation? GetAdjustNewLinesOperation(in SyntaxToken previousToken, in SyntaxToken currentToken, in NextGetAdjustNewLinesOperation nextOperation) + { + var needsNewLine = NeedsNewLine(currentToken, _options); + return needsNewLine switch + { + true => CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines), + false => null, + _ => base.GetAdjustNewLinesOperation(in previousToken, in currentToken, in nextOperation), + }; } public override void AddAlignTokensOperations(List list, SyntaxNode node, in NextAlignTokensOperationAction nextOperation) @@ -426,45 +509,6 @@ public override void AddSuppressOperations(List list, SyntaxN list.RemoveAll(s_predicate); } } - - private readonly struct CachedOptions : IEquatable - { - public readonly bool NewLinesForBracesInObjectCollectionArrayInitializers; - - public CachedOptions(AnalyzerConfigOptions? options) - { - NewLinesForBracesInObjectCollectionArrayInitializers = GetOptionOrDefault(options, CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers); - } - - public static bool operator ==(CachedOptions left, CachedOptions right) - => left.Equals(right); - - public static bool operator !=(CachedOptions left, CachedOptions right) - => !(left == right); - - private static T GetOptionOrDefault(AnalyzerConfigOptions? options, Option2 option) - { - if (options is null) - return option.DefaultValue; - - return options.GetOption(option); - } - - public override bool Equals(object? obj) - => obj is CachedOptions options && Equals(options); - - public bool Equals(CachedOptions other) - { - return NewLinesForBracesInObjectCollectionArrayInitializers == other.NewLinesForBracesInObjectCollectionArrayInitializers; - } - - public override int GetHashCode() - { - var hashCode = 0; - hashCode = (hashCode << 1) + (NewLinesForBracesInObjectCollectionArrayInitializers ? 1 : 0); - return hashCode; - } - } } } } diff --git a/src/Features/CSharp/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.cs index 9e7acb5c866e3..0aa33c0d8cf2b 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/InterpolatedStringBraceCompletionService.cs @@ -59,33 +59,35 @@ public static async Task IsPositionInInterpolatedStringContextAsync(Docume var start = position - 1; if (start < 0) - { return false; - } // Check if the user is typing an interpolated or interpolated verbatim string. // If the preceding character(s) are not '$' or '$@' then we can't be starting an interpolated string. if (text[start] == '@') { - start--; - - if (start < 0) - { + if (--start < 0) return false; - } } if (text[start] != '$') - { return false; - } // Verify that we are actually in an location allowed for an interpolated string. - // Note that the quote has not yet been typed so we don't actually know if we're in an interpolated string. var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var token = root.FindTokenOnLeftOfPosition(start); - return root.SyntaxTree.IsExpressionContext(start, token, attributes: false, cancellationToken: cancellationToken) - || root.SyntaxTree.IsStatementContext(start, token, cancellationToken); + + var token = root.FindToken(start); + if (token.Kind() is not SyntaxKind.InterpolatedStringStartToken and + not SyntaxKind.InterpolatedVerbatimStringStartToken and + not SyntaxKind.StringLiteralToken and + not SyntaxKind.IdentifierToken) + { + return false; + } + + var previousToken = token.GetPreviousToken(); + + return root.SyntaxTree.IsExpressionContext(token.SpanStart, previousToken, attributes: true, cancellationToken) + || root.SyntaxTree.IsStatementContext(token.SpanStart, previousToken, cancellationToken); } } } diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx index 345282c97cc4e..699c6e9693e17 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx @@ -630,4 +630,10 @@ Selection cannot include top-level statements + + Convert to raw string + + + Convert to raw string (no indent) + \ No newline at end of file diff --git a/src/Features/CSharp/Portable/CodeFixes/FixReturnType/CSharpFixReturnTypeCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/FixReturnType/CSharpFixReturnTypeCodeFixProvider.cs index 6954f504790b8..9a34aa77c5a5a 100644 --- a/src/Features/CSharp/Portable/CodeFixes/FixReturnType/CSharpFixReturnTypeCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/FixReturnType/CSharpFixReturnTypeCodeFixProvider.cs @@ -49,9 +49,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var analyzedTypes = await TryGetOldAndNewReturnTypeAsync(document, diagnostics, cancellationToken).ConfigureAwait(false); if (analyzedTypes == default) - { return; - } if (IsVoid(analyzedTypes.declarationToFix) && IsVoid(analyzedTypes.fixedDeclaration)) { @@ -67,7 +65,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) return; static bool IsVoid(TypeSyntax typeSyntax) - => typeSyntax is PredefinedTypeSyntax predefined && predefined.Keyword.IsKind(SyntaxKind.VoidKeyword); + => typeSyntax is PredefinedTypeSyntax { Keyword.RawKind: (int)SyntaxKind.VoidKeyword }; } private static async Task<(TypeSyntax declarationToFix, TypeSyntax fixedDeclaration)> TryGetOldAndNewReturnTypeAsync( @@ -78,37 +76,28 @@ static bool IsVoid(TypeSyntax typeSyntax) var node = location.FindNode(getInnermostNodeForTie: true, cancellationToken); var returnedValue = node is ReturnStatementSyntax returnStatement ? returnStatement.Expression : node; if (returnedValue == null) - { return default; - } var (declarationTypeToFix, useTask) = TryGetDeclarationTypeToFix(node); if (declarationTypeToFix == null) - { return default; - } var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var returnedType = semanticModel.GetTypeInfo(returnedValue, cancellationToken).Type; - if (returnedType == null) - { - returnedType = semanticModel.Compilation.ObjectType; - } + returnedType ??= semanticModel.Compilation.ObjectType; TypeSyntax fixedDeclaration; if (useTask) { var taskOfTType = semanticModel.Compilation.TaskOfTType(); if (taskOfTType is null) - { return default; - } - fixedDeclaration = taskOfTType.Construct(returnedType).GenerateTypeSyntax(); + fixedDeclaration = taskOfTType.Construct(returnedType).GenerateTypeSyntax(allowVar: false); } else { - fixedDeclaration = returnedType.GenerateTypeSyntax(); + fixedDeclaration = returnedType.GenerateTypeSyntax(allowVar: false); } fixedDeclaration = fixedDeclaration.WithAdditionalAnnotations(Simplifier.Annotation).WithTriviaFrom(declarationTypeToFix); @@ -126,40 +115,27 @@ protected override async Task FixAllAsync(Document document, ImmutableArray TryGetReturnTypeToFix(a)).FirstOrDefault(p => p != default); + return node.GetAncestors().Select(TryGetReturnTypeToFix).FirstOrDefault(p => p.type != null); - // Local functions static (TypeSyntax type, bool useTask) TryGetReturnTypeToFix(SyntaxNode containingMember) { - switch (containingMember) + return containingMember switch { - case MethodDeclarationSyntax method: - // void M() { return 1; } - // async Task M() { return 1; } - return (method.ReturnType, IsAsync(method.Modifiers)); - - case LocalFunctionStatementSyntax localFunction: - // void local() { return 1; } - // async Task local() { return 1; } - return (localFunction.ReturnType, IsAsync(localFunction.Modifiers)); - - default: - return default; - } - } - - static bool IsAsync(SyntaxTokenList modifiers) - { - return modifiers.Any(SyntaxKind.AsyncKeyword); + // void M() { return 1; } + // async Task M() { return 1; } + MethodDeclarationSyntax method => (method.ReturnType, method.Modifiers.Any(SyntaxKind.AsyncKeyword)), + // void local() { return 1; } + // async Task local() { return 1; } + LocalFunctionStatementSyntax localFunction => (localFunction.ReturnType, localFunction.Modifiers.Any(SyntaxKind.AsyncKeyword)), + _ => default, + }; } } private class MyCodeAction : CodeAction.DocumentChangeAction { public MyCodeAction(Func> createChangedDocument) - : base(CSharpFeaturesResources.Fix_return_type, - createChangedDocument, - CSharpFeaturesResources.Fix_return_type) + : base(CSharpFeaturesResources.Fix_return_type, createChangedDocument, nameof(CSharpFeaturesResources.Fix_return_type)) { } } diff --git a/src/Features/CSharp/Portable/CodeFixes/Suppression/CSharpSuppressionCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/Suppression/CSharpSuppressionCodeFixProvider.cs index 5c7f149b05ce2..bb6c888c8024b 100644 --- a/src/Features/CSharp/Portable/CodeFixes/Suppression/CSharpSuppressionCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/Suppression/CSharpSuppressionCodeFixProvider.cs @@ -10,12 +10,13 @@ using System.Globalization; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeFixes.Suppression; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; @@ -31,27 +32,27 @@ public CSharpSuppressionCodeFixProvider() { } - protected override SyntaxTriviaList CreatePragmaRestoreDirectiveTrivia(Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine) + protected override SyntaxTriviaList CreatePragmaRestoreDirectiveTrivia(Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine, CancellationToken cancellationToken) { var restoreKeyword = SyntaxFactory.Token(SyntaxKind.RestoreKeyword); - return CreatePragmaDirectiveTrivia(restoreKeyword, diagnostic, formatNode, needsLeadingEndOfLine, needsTrailingEndOfLine); + return CreatePragmaDirectiveTrivia(restoreKeyword, diagnostic, formatNode, needsLeadingEndOfLine, needsTrailingEndOfLine, cancellationToken); } protected override SyntaxTriviaList CreatePragmaDisableDirectiveTrivia( - Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine) + Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine, CancellationToken cancellationToken) { var disableKeyword = SyntaxFactory.Token(SyntaxKind.DisableKeyword); - return CreatePragmaDirectiveTrivia(disableKeyword, diagnostic, formatNode, needsLeadingEndOfLine, needsTrailingEndOfLine); + return CreatePragmaDirectiveTrivia(disableKeyword, diagnostic, formatNode, needsLeadingEndOfLine, needsTrailingEndOfLine, cancellationToken); } private static SyntaxTriviaList CreatePragmaDirectiveTrivia( - SyntaxToken disableOrRestoreKeyword, Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine) + SyntaxToken disableOrRestoreKeyword, Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine, CancellationToken cancellationToken) { var diagnosticId = GetOrMapDiagnosticId(diagnostic, out var includeTitle); var id = SyntaxFactory.IdentifierName(diagnosticId); var ids = new SeparatedSyntaxList().Add(id); var pragmaDirective = SyntaxFactory.PragmaWarningDirectiveTrivia(disableOrRestoreKeyword, ids, true); - pragmaDirective = (PragmaWarningDirectiveTriviaSyntax)formatNode(pragmaDirective); + pragmaDirective = (PragmaWarningDirectiveTriviaSyntax)formatNode(pragmaDirective, cancellationToken); var pragmaDirectiveTrivia = SyntaxFactory.Trivia(pragmaDirective); var endOfLineTrivia = SyntaxFactory.CarriageReturnLineFeed; var triviaList = SyntaxFactory.TriviaList(pragmaDirectiveTrivia); @@ -98,8 +99,8 @@ protected override SyntaxNode AddGlobalSuppressMessageAttribute( ISymbol targetSymbol, INamedTypeSymbol suppressMessageAttribute, Diagnostic diagnostic, - Workspace workspace, - Compilation compilation, + HostWorkspaceServices services, + SyntaxFormattingOptions options, IAddImportsService addImportsService, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs index 8b3f95398ff49..d0e16360066bf 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs @@ -125,9 +125,8 @@ private static async Task UpdateDocumentAsync( typeParameters: typeParameters.ToImmutableArray(), parameters: parameters.AddRange(capturesAsParameters)); - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var defaultOptions = new CodeGenerationOptions(options: options); - var method = MethodGenerator.GenerateMethodDeclaration(methodSymbol, CodeGenerationDestination.Unspecified, defaultOptions, root.SyntaxTree.Options); + var defaultOptions = await CSharpCodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, document, cancellationToken).ConfigureAwait(false); + var method = MethodGenerator.GenerateMethodDeclaration(methodSymbol, CodeGenerationDestination.Unspecified, defaultOptions, cancellationToken); var generator = s_generator; var editor = new SyntaxEditor(root, generator); @@ -249,7 +248,7 @@ private static async Task UpdateDocumentAsync( } private static bool SupportsNonTrailingNamedArguments(ParseOptions options) - => ((CSharpParseOptions)options).LanguageVersion >= LanguageVersion.CSharp7_2; + => options.LanguageVersion() >= LanguageVersion.CSharp7_2; private static SyntaxNode GenerateArgument(IParameterSymbol p, string name, bool shouldUseNamedArguments = false) => s_generator.Argument(shouldUseNamedArguments ? name : null, p.RefKind, name.ToIdentifierName()); diff --git a/src/Features/CSharp/Portable/CodeRefactorings/LambdaSimplifier/LambdaSimplifierCodeRefactoringProvider.Rewriter.cs b/src/Features/CSharp/Portable/CodeRefactorings/LambdaSimplifier/LambdaSimplifierCodeRefactoringProvider.Rewriter.cs deleted file mode 100644 index 5777b3900fa1f..0000000000000 --- a/src/Features/CSharp/Portable/CodeRefactorings/LambdaSimplifier/LambdaSimplifierCodeRefactoringProvider.Rewriter.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Linq; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Shared.Utilities; - -namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.LambdaSimplifier -{ - internal partial class LambdaSimplifierCodeRefactoringProvider - { - private class Rewriter : CSharpSyntaxRewriter - { - private readonly SemanticDocument _document; - private readonly Func _predicate; - private readonly CancellationToken _cancellationToken; - - public Rewriter( - SemanticDocument document, - Func predicate, - CancellationToken cancellationToken) - { - _document = document; - _predicate = predicate; - _cancellationToken = cancellationToken; - } - - private ExpressionSyntax SimplifyInvocation(InvocationExpressionSyntax invocation) - { - var expression = invocation.Expression; - if (expression is MemberAccessExpressionSyntax memberAccess) - { - var symbolMap = SemanticMap.From(_document.SemanticModel, memberAccess.Expression, _cancellationToken); - var anySideEffects = symbolMap.AllReferencedSymbols.Any(s => - s.Kind is SymbolKind.Method or SymbolKind.Property); - - if (anySideEffects) - { - var annotation = WarningAnnotation.Create(CSharpFeaturesResources.Warning_Expression_may_change_code_meaning); - expression = expression.ReplaceNode(memberAccess.Expression, memberAccess.Expression.WithAdditionalAnnotations(annotation)); - } - } - - return expression.Parenthesize() - .WithAdditionalAnnotations(Formatter.Annotation); - } - - public override SyntaxNode VisitSimpleLambdaExpression(SimpleLambdaExpressionSyntax node) - { - if (_predicate(node) && CanSimplify(_document, node, _cancellationToken)) - { - var invocation = TryGetInvocationExpression(node.Body); - if (invocation != null) - { - return SimplifyInvocation(invocation); - } - } - - return base.VisitSimpleLambdaExpression(node); - } - - public override SyntaxNode VisitParenthesizedLambdaExpression(ParenthesizedLambdaExpressionSyntax node) - { - if (_predicate(node) && CanSimplify(_document, node, _cancellationToken)) - { - var invocation = TryGetInvocationExpression(node.Body); - if (invocation != null) - { - return SimplifyInvocation(invocation); - } - } - - return base.VisitParenthesizedLambdaExpression(node); - } - } - } -} diff --git a/src/Features/CSharp/Portable/CodeRefactorings/LambdaSimplifier/LambdaSimplifierCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/LambdaSimplifier/LambdaSimplifierCodeRefactoringProvider.cs deleted file mode 100644 index 2d672d9b145d7..0000000000000 --- a/src/Features/CSharp/Portable/CodeRefactorings/LambdaSimplifier/LambdaSimplifierCodeRefactoringProvider.cs +++ /dev/null @@ -1,293 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.LambdaSimplifier -{ - // Disabled due to: https://github.com/dotnet/roslyn/issues/5835 & https://github.com/dotnet/roslyn/pull/6642 - // [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.SimplifyLambda)] - internal partial class LambdaSimplifierCodeRefactoringProvider : CodeRefactoringProvider - { - public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) - { - var (document, textSpan, cancellationToken) = context; - if (cancellationToken.IsCancellationRequested) - { - return; - } - - if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) - { - return; - } - - var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); - - var lambda = await context.TryGetRelevantNodeAsync().ConfigureAwait(false); - if (lambda == null) - { - return; - } - - if (!CanSimplify(semanticDocument, lambda as SimpleLambdaExpressionSyntax, cancellationToken) && - !CanSimplify(semanticDocument, lambda as ParenthesizedLambdaExpressionSyntax, cancellationToken)) - { - return; - } - - context.RegisterRefactoring( - new MyCodeAction( - CSharpFeaturesResources.Simplify_lambda_expression, - c => SimplifyLambdaAsync(document, lambda, c)), - lambda.Span); - - context.RegisterRefactoring( - new MyCodeAction( - CSharpFeaturesResources.Simplify_all_occurrences, - c => SimplifyAllLambdasAsync(document, c)), - lambda.Span); - } - - private static async Task SimplifyLambdaAsync( - Document document, - SyntaxNode lambda, - CancellationToken cancellationToken) - { - var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); - var rewriter = new Rewriter(semanticDocument, n => n == lambda, cancellationToken); - var result = rewriter.Visit(semanticDocument.Root); - return document.WithSyntaxRoot(result); - } - - private static async Task SimplifyAllLambdasAsync( - Document document, - CancellationToken cancellationToken) - { - var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); - var rewriter = new Rewriter(semanticDocument, n => true, cancellationToken); - var result = rewriter.Visit(semanticDocument.Root); - return document.WithSyntaxRoot(result); - } - - private static bool CanSimplify( - SemanticDocument document, - SimpleLambdaExpressionSyntax node, - CancellationToken cancellationToken) - { - if (node == null) - { - return false; - } - - var paramName = node.Parameter.Identifier; - var invocation = TryGetInvocationExpression(node.Body); - return CanSimplify(document, node, new List() { paramName }, invocation, cancellationToken); - } - - private static bool CanSimplify( - SemanticDocument document, - ParenthesizedLambdaExpressionSyntax node, - CancellationToken cancellationToken) - { - if (node == null) - { - return false; - } - - var paramNames = node.ParameterList.Parameters.Select(p => p.Identifier).ToList(); - var invocation = TryGetInvocationExpression(node.Body); - return CanSimplify(document, node, paramNames, invocation, cancellationToken); - } - - private static bool CanSimplify( - SemanticDocument document, - ExpressionSyntax lambda, - List paramNames, - InvocationExpressionSyntax invocation, - CancellationToken cancellationToken) - { - if (invocation == null) - { - return false; - } - - if (invocation.ArgumentList.Arguments.Count != paramNames.Count) - { - return false; - } - - for (var i = 0; i < paramNames.Count; i++) - { - var argument = invocation.ArgumentList.Arguments[i]; - if (argument.NameColon != null || - argument.RefOrOutKeyword.Kind() != SyntaxKind.None || - !argument.Expression.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax identifierName)) - { - return false; - } - - if (identifierName.Identifier.ValueText != paramNames[i].ValueText) - { - return false; - } - } - - var semanticModel = document.SemanticModel; - var lambdaSemanticInfo = semanticModel.GetSymbolInfo(lambda, cancellationToken); - var invocationSemanticInfo = semanticModel.GetSymbolInfo(invocation, cancellationToken); - if (lambdaSemanticInfo.Symbol == null || - invocationSemanticInfo.Symbol == null) - { - // Don't offer this if there are any errors or ambiguities. - return false; - } - - if (lambdaSemanticInfo.Symbol is not IMethodSymbol lambdaMethod || invocationSemanticInfo.Symbol is not IMethodSymbol invocationMethod) - { - return false; - } - - // TODO(cyrusn): Handle extension methods as well. - if (invocationMethod.IsExtensionMethod) - { - return false; - } - - // Check if any of the parameter is of Type Dynamic - foreach (var parameter in lambdaMethod.Parameters) - { - if (parameter.Type != null && parameter.Type.Kind == SymbolKind.DynamicType) - { - return false; - } - } - - // Check if the parameter and return types match between the lambda and the - // invocation. Note: return types can be covariant and argument types can be - // contravariant. - if (lambdaMethod.ReturnsVoid != invocationMethod.ReturnsVoid || - lambdaMethod.Parameters.Length != invocationMethod.Parameters.Length) - { - return false; - } - - if (!lambdaMethod.ReturnsVoid) - { - // Return type has to be covariant. - var conversion = document.SemanticModel.Compilation.ClassifyConversion( - invocationMethod.ReturnType, lambdaMethod.ReturnType); - if (!conversion.IsIdentityOrImplicitReference()) - { - return false; - } - } - - // Parameter types have to be contravariant. - for (var i = 0; i < lambdaMethod.Parameters.Length; i++) - { - var conversion = document.SemanticModel.Compilation.ClassifyConversion( - lambdaMethod.Parameters[i].Type, invocationMethod.Parameters[i].Type); - - if (!conversion.IsIdentityOrImplicitReference()) - { - return false; - } - } - - if (WouldCauseAmbiguity(lambda, invocation, semanticModel, cancellationToken)) - { - return false; - } - - // Looks like something we can simplify. - return true; - } - - // Ensure that if we replace the invocation with its expression that its expression will - // bind unambiguously. This can happen with awesome cases like: -#if false - static void Goo(T x) where T : class { } - static void Bar(Action x) { } - static void Bar(Action x) { } - static void Main() - { - Bar(x => Goo(x)); // error CS0121: The call is ambiguous between the following methods or properties: 'A.Bar(System.Action)' and 'A.Bar(System.Action)' - } -#endif - private static bool WouldCauseAmbiguity( - ExpressionSyntax lambda, - InvocationExpressionSyntax invocation, - SemanticModel oldSemanticModel, - CancellationToken cancellationToken) - { - var annotation = new SyntaxAnnotation(); - - // In order to check if there will be a problem, we actually make the change, fork the - // compilation, and then verify that the new expression bound unambiguously. - var oldExpression = invocation.Expression.WithAdditionalAnnotations(annotation); - var oldCompilation = oldSemanticModel.Compilation; - var oldTree = oldSemanticModel.SyntaxTree; - var oldRoot = oldTree.GetRoot(cancellationToken); - - var newRoot = oldRoot.ReplaceNode(lambda, oldExpression); - - var newTree = oldTree.WithRootAndOptions(newRoot, oldTree.Options); - - var newCompilation = oldCompilation.ReplaceSyntaxTree(oldTree, newTree); - var newExpression = newTree.GetRoot(cancellationToken).GetAnnotatedNodesAndTokens(annotation).First().AsNode(); - var newSemanticModel = newCompilation.GetSemanticModel(newTree); - - var info = newSemanticModel.GetSymbolInfo(newExpression, cancellationToken); - - return info.CandidateReason != CandidateReason.None; - } - - private static InvocationExpressionSyntax TryGetInvocationExpression( - SyntaxNode lambdaBody) - { - if (lambdaBody is ExpressionSyntax exprBody) - { - return exprBody.WalkDownParentheses() as InvocationExpressionSyntax; - } - else if (lambdaBody is BlockSyntax block) - { - if (block.Statements.Count == 1) - { - var statement = block.Statements.First(); - if (statement is ReturnStatementSyntax returnStatement) - { - return returnStatement.Expression.WalkDownParentheses() as InvocationExpressionSyntax; - } - else if (statement is ExpressionStatementSyntax exprStatement) - { - return exprStatement.Expression.WalkDownParentheses() as InvocationExpressionSyntax; - } - } - } - - return null; - } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } - } -} diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs index e8abbbb2b2cf2..24be9b03fd663 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs @@ -121,7 +121,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); + var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.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 19ef4ebe9d3eb..74bae4627819c 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs @@ -33,14 +33,6 @@ internal sealed class UseRecursivePatternsCodeRefactoringProvider : CodeRefactor private static readonly PatternSyntax s_trueConstantPattern = ConstantPattern(LiteralExpression(TrueLiteralExpression)); private static readonly PatternSyntax s_falseConstantPattern = ConstantPattern(LiteralExpression(FalseLiteralExpression)); - private static readonly Func s_canConvertToSubpattern = - (name, model) => model.GetSymbolInfo(name).Symbol is - { - IsStatic: false, - Kind: SymbolKind.Property or SymbolKind.Field, - ContainingType: not { SpecialType: SpecialType.System_Nullable_T } - }; - [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public UseRecursivePatternsCodeRefactoringProvider() @@ -57,7 +49,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - if (((CSharpParseOptions)root.SyntaxTree.Options).LanguageVersion < LanguageVersion.CSharp9) + if (root.SyntaxTree.Options.LanguageVersion() < LanguageVersion.CSharp9) return; var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -115,8 +107,6 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte { var leftSubpattern = CreateSubpattern(leftNames, CreatePattern(leftReceiver, leftTarget, leftFlipped)); var rightSubpattern = CreateSubpattern(rightNames, CreatePattern(rightReceiver, rightTarget, rightFlipped)); - // If the common receiver is null, it's an implicit `this` reference in source. - // For instance, `prop == 1 && field == 2` would be converted to `this is { prop: 1, field: 2 }` var replacement = IsPatternExpression(commonReceiver, RecursivePattern(leftSubpattern, rightSubpattern)); return root.ReplaceNode(logicalAnd, AdjustBinaryExpressionOperands(logicalAnd, replacement)); }; @@ -237,12 +227,7 @@ static PatternSyntax AddSubpattern(PatternSyntax containingPattern, SubpatternSy { if (left is null || right is null) return left ?? right; - var leftSubpatterns = left.Subpatterns.GetWithSeparators(); - if (leftSubpatterns.Any() && !leftSubpatterns.Last().IsToken) - leftSubpatterns = leftSubpatterns.Add(Token(CommaToken)); - var rightSubpatterns = right.Subpatterns.GetWithSeparators(); - var list = new SyntaxNodeOrTokenList(leftSubpatterns.Concat(rightSubpatterns)); - return left.WithSubpatterns(SeparatedList(list)); + return left.WithSubpatterns(left.Subpatterns.AddRange(right.Subpatterns)); } } @@ -295,7 +280,8 @@ private static (PatternSyntax ContainingPattern, ImmutableArray d.Identifier.ValueText == identifierName.Identifier.ValueText) .FirstOrDefault(); - if (designation is not { Parent: PatternSyntax containingPattern }) + // Excluding list patterns because those cannot be combined with a recursive pattern. + if (designation is not { Parent: PatternSyntax(not SyntaxKind.ListPattern) containingPattern }) return null; // Only the following patterns can directly contain a variable designation. @@ -360,10 +346,21 @@ LessThanOrEqualExpression or private static SubpatternSyntax CreateSubpattern(ImmutableArray names, PatternSyntax pattern) { Debug.Assert(!names.IsDefaultOrEmpty); - var subpattern = Subpattern(names[0], pattern); - for (var i = 1; i < names.Length; i++) - subpattern = Subpattern(names[i], RecursivePattern(subpattern)); - return subpattern; + + if (names.Length > 1 && names[0].SyntaxTree.Options.LanguageVersion() >= LanguageVersion.CSharp10) + { + ExpressionSyntax expression = names[^1]; + for (var i = names.Length - 2; i >= 0; i--) + expression = MemberAccessExpression(SimpleMemberAccessExpression, expression, names[i]); + return SyntaxFactory.Subpattern(ExpressionColon(expression, Token(ColonToken)), pattern); + } + else + { + var subpattern = Subpattern(names[0], pattern); + for (var i = 1; i < names.Length; i++) + subpattern = Subpattern(names[i], RecursivePattern(subpattern)); + return subpattern; + } } private static SubpatternSyntax Subpattern(IdentifierNameSyntax name, PatternSyntax pattern) @@ -409,6 +406,8 @@ private static (ExpressionSyntax CommonReceiver, ImmutableArray identifierName != lastName); } + // If the common receiver is null, it's an implicit `this` reference in source. + // For instance, `prop == 1 && field == 2` would be converted to `this is { prop: 1, field: 2 }` return (commonReceiver ?? ThisExpression(), leftNames.ToImmutable(), rightNames.ToImmutable()); static bool TryGetInnermostReceiver(ExpressionSyntax node, ArrayBuilder builder, [NotNullWhen(true)] out ExpressionSyntax? receiver, SemanticModel model) @@ -438,7 +437,19 @@ static bool TryGetInnermostReceiver(ExpressionSyntax node, ArrayBuilder builder, SemanticModel model) - => GetInnermostReceiver(node, model, s_canConvertToSubpattern, builder); + { + return GetInnermostReceiver(node, model, CanConvertToSubpattern, builder); + + static bool CanConvertToSubpattern(IdentifierNameSyntax name, SemanticModel model) + { + return model.GetSymbolInfo(name).Symbol is + { + IsStatic: false, + Kind: SymbolKind.Property or SymbolKind.Field, + ContainingType: not { SpecialType: SpecialType.System_Nullable_T } + }; + } + } private static ExpressionSyntax? GetInnermostReceiver( ExpressionSyntax node, TArg arg, diff --git a/src/Features/CSharp/Portable/Completion/CSharpCompletionOptions.cs b/src/Features/CSharp/Portable/Completion/CSharpCompletionOptions.cs index c40fe40e32ea1..e05db432b493a 100644 --- a/src/Features/CSharp/Portable/Completion/CSharpCompletionOptions.cs +++ b/src/Features/CSharp/Portable/Completion/CSharpCompletionOptions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using Microsoft.CodeAnalysis.Options; diff --git a/src/Features/CSharp/Portable/Completion/CSharpCompletionService.cs b/src/Features/CSharp/Portable/Completion/CSharpCompletionService.cs index 195776f39cc9b..e1f177289fd7c 100644 --- a/src/Features/CSharp/Portable/Completion/CSharpCompletionService.cs +++ b/src/Features/CSharp/Portable/Completion/CSharpCompletionService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using System.Threading; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs index 9aaf3284481d2..28f9b96544ec1 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/CompletionUtilities.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.DeclarationInfo.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.DeclarationInfo.cs index 83a40a5e34c7e..2dd132d524299 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.DeclarationInfo.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.DeclarationInfo.cs @@ -72,7 +72,12 @@ internal static async Task GetDeclarationInfoAsync(Document return result; } - return default; + return new NameDeclarationInfo( + possibleSymbolKinds: ImmutableArray.Empty, + accessibility: null, + declarationModifiers: default, + type: null, + alias: null); } private static bool IsTupleTypeElement( diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs index 14594202831c4..590db74622cdf 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs @@ -16,6 +16,8 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServices; @@ -67,13 +69,27 @@ public override async Task ProvideCompletionsAsync(CompletionContext completionC } var nameInfo = await NameDeclarationInfo.GetDeclarationInfoAsync(document, position, cancellationToken).ConfigureAwait(false); + using var _ = ArrayBuilder<(string name, SymbolKind kind)>.GetInstance(out var result); + + // Suggest names from existing overloads. + if (nameInfo.PossibleSymbolKinds.Any(k => k.SymbolKind == SymbolKind.Parameter)) + { + var (_, partialSemanticModel) = await document.GetPartialSemanticModelAsync(cancellationToken).ConfigureAwait(false); + if (partialSemanticModel is not null) + AddNamesFromExistingOverloads(context, partialSemanticModel, result, cancellationToken); + } + var baseNames = GetBaseNames(semanticModel, nameInfo); - if (baseNames == default) + if (baseNames != default) { - return; + await GetRecommendedNamesAsync(baseNames, nameInfo, context, document, result, cancellationToken).ConfigureAwait(false); } - var recommendedNames = await GetRecommendedNamesAsync(baseNames, nameInfo, context, document, cancellationToken).ConfigureAwait(false); + var recommendedNames = result.ToImmutable(); + + if (recommendedNames.IsEmpty) + return; + var sortValue = 0; foreach (var (name, kind) in recommendedNames) { @@ -225,21 +241,39 @@ private static Glyph GetGlyph(SymbolKind kind, Accessibility? declaredAccessibil return (type, wasPlural); } - private static async Task> GetRecommendedNamesAsync( + private static async Task GetRecommendedNamesAsync( ImmutableArray> baseNames, NameDeclarationInfo declarationInfo, CSharpSyntaxContext context, Document document, + ArrayBuilder<(string name, SymbolKind kind)> result, CancellationToken cancellationToken) { - var rules = await document.GetNamingRulesAsync(FallbackNamingRules.CompletionOfferingRules, cancellationToken).ConfigureAwait(false); + var rules = await document.GetNamingRulesAsync(FallbackNamingRules.CompletionFallbackRules, cancellationToken).ConfigureAwait(false); + var supplementaryRules = FallbackNamingRules.CompletionSupplementaryRules; var semanticFactsService = context.GetLanguageService(); using var _1 = PooledHashSet.GetInstance(out var seenBaseNames); using var _2 = PooledHashSet.GetInstance(out var seenUniqueNames); - using var _3 = ArrayBuilder<(string name, SymbolKind kind)>.GetInstance(out var result); foreach (var kind in declarationInfo.PossibleSymbolKinds) + { + ProcessRules(rules, firstMatchOnly: true, kind, baseNames, declarationInfo, context, result, semanticFactsService, seenBaseNames, seenUniqueNames, cancellationToken); + ProcessRules(supplementaryRules, firstMatchOnly: false, kind, baseNames, declarationInfo, context, result, semanticFactsService, seenBaseNames, seenUniqueNames, cancellationToken); + } + + static void ProcessRules( + ImmutableArray rules, + bool firstMatchOnly, + SymbolSpecification.SymbolKindOrTypeKind kind, + ImmutableArray> baseNames, + NameDeclarationInfo declarationInfo, + CSharpSyntaxContext context, + ArrayBuilder<(string name, SymbolKind kind)> result, + ISemanticFactsService semanticFactsService, + PooledHashSet seenBaseNames, + PooledHashSet seenUniqueNames, + CancellationToken cancellationToken) { // There's no special glyph for local functions. // We don't need to differentiate them at this point. @@ -274,11 +308,62 @@ private static Glyph GetGlyph(SymbolKind kind, Accessibility? declaredAccessibil result.Add((uniqueName.Text, symbolKind)); } } + + if (firstMatchOnly) + { + // Only consider the first matching specification for each potential symbol or type kind. + // https://github.com/dotnet/roslyn/issues/36248 + break; + } + } + } + } + } + + private static void AddNamesFromExistingOverloads(CSharpSyntaxContext context, SemanticModel semanticModel, ArrayBuilder<(string name, SymbolKind kind)> result, CancellationToken cancellationToken) + { + var namedType = semanticModel.GetEnclosingNamedType(context.Position, cancellationToken); + if (namedType is null) + return; + + var parameterSyntax = context.LeftToken.GetAncestor(n => n.IsKind(SyntaxKind.Parameter)) as ParameterSyntax; + if (parameterSyntax is not { Type: { } parameterType, Parent.Parent: BaseMethodDeclarationSyntax baseMethod }) + return; + + var methodParameterType = semanticModel.GetTypeInfo(parameterType, cancellationToken).Type; + if (methodParameterType is null) + return; + + var overloads = GetOverloads(namedType, baseMethod); + if (overloads.IsEmpty) + return; + + var currentParameterNames = baseMethod.ParameterList.Parameters.Select(p => p.Identifier.ValueText).ToImmutableHashSet(); + + foreach (var overload in overloads) + { + foreach (var overloadParameter in overload.Parameters) + { + if (!currentParameterNames.Contains(overloadParameter.Name) && + methodParameterType.Equals(overloadParameter.Type, SymbolEqualityComparer.Default)) + { + result.Add((overloadParameter.Name, SymbolKind.Parameter)); } } } - return result.ToImmutable(); + return; + + // Local functions + static ImmutableArray GetOverloads(INamedTypeSymbol namedType, BaseMethodDeclarationSyntax baseMethod) + { + return baseMethod switch + { + MethodDeclarationSyntax method => namedType.GetMembers(method.Identifier.ValueText).OfType().ToImmutableArray(), + ConstructorDeclarationSyntax constructor => namedType.GetMembers(WellKnownMemberNames.InstanceConstructorName).OfType().ToImmutableArray(), + _ => ImmutableArray.Empty + }; + } } /// diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.CompletionSymbolDisplay.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.CompletionSymbolDisplay.cs new file mode 100644 index 0000000000000..44dac7a5bde72 --- /dev/null +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.CompletionSymbolDisplay.cs @@ -0,0 +1,120 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Text; +using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers +{ + internal partial class ExplicitInterfaceMemberCompletionProvider + { + private static class CompletionSymbolDisplay + { + public static string ToDisplayString(ISymbol symbol) + => symbol switch + { + IEventSymbol eventSymbol => ToDisplayString(eventSymbol), + IPropertySymbol propertySymbol => ToDisplayString(propertySymbol), + IMethodSymbol methodSymbol => ToDisplayString(methodSymbol), + _ => "" // This shouldn't happen. + }; + + private static string ToDisplayString(IEventSymbol symbol) + => symbol.Name; + + private static string ToDisplayString(IPropertySymbol symbol) + { + using var _ = PooledStringBuilder.GetInstance(out var builder); + + if (symbol.IsIndexer) + { + builder.Append("this"); + } + else + { + builder.Append(symbol.Name); + } + + if (symbol.Parameters.Length > 0) + { + builder.Append('['); + AddParameters(symbol.Parameters, builder); + builder.Append(']'); + } + + return builder.ToString(); + } + + private static string ToDisplayString(IMethodSymbol symbol) + { + using var _ = PooledStringBuilder.GetInstance(out var builder); + switch (symbol.MethodKind) + { + case MethodKind.Ordinary: + builder.Append(symbol.Name); + break; + case MethodKind.UserDefinedOperator: + case MethodKind.BuiltinOperator: + builder.Append("operator "); + builder.Append(SyntaxFacts.GetText(SyntaxFacts.GetOperatorKind(symbol.MetadataName))); + break; + case MethodKind.Conversion: + builder.Append("operator "); + AddType(symbol.ReturnType, builder); + break; + } + + AddTypeArguments(symbol, builder); + builder.Append('('); + AddParameters(symbol.Parameters, builder); + builder.Append(')'); + return builder.ToString(); + } + + private static void AddParameters(ImmutableArray parameters, StringBuilder builder) + { + builder.AppendJoinedValues(", ", parameters, static (parameter, builder) => + { + builder.Append(parameter.RefKind switch + { + RefKind.Out => "out ", + RefKind.Ref => "ref ", + RefKind.In => "in ", + _ => "" + }); + + if (parameter.IsParams) + { + builder.Append("params "); + } + + AddType(parameter.Type, builder); + builder.Append($" {parameter.Name.EscapeIdentifier()}"); + }); + } + + private static void AddTypeArguments(IMethodSymbol symbol, StringBuilder builder) + { + if (symbol.TypeArguments.Length > 0) + { + builder.Append('<'); + builder.AppendJoinedValues(", ", symbol.TypeArguments, static (symbol, builder) => builder.Append(symbol.Name.EscapeIdentifier())); + builder.Append('>'); + } + } + + private static void AddType(ITypeSymbol symbol, StringBuilder builder) + { + builder.Append(symbol.ToNameDisplayString()); + if (symbol.NullableAnnotation == NullableAnnotation.Annotated) + { + builder.Append('?'); + } + } + } + } +} diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs index 58f311c6ec386..7f19014ce6918 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ExplicitInterfaceMemberCompletionProvider.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Immutable; using System.Composition; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; @@ -24,18 +25,6 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers [ExtensionOrder(After = nameof(UnnamedSymbolCompletionProvider))] internal partial class ExplicitInterfaceMemberCompletionProvider : LSPCompletionProvider { - private static readonly SymbolDisplayFormat s_signatureDisplayFormat = - new(genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - memberOptions: - SymbolDisplayMemberOptions.IncludeParameters, - parameterOptions: - SymbolDisplayParameterOptions.IncludeName | - SymbolDisplayParameterOptions.IncludeType | - SymbolDisplayParameterOptions.IncludeParamsRefOut, - miscellaneousOptions: - SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | - SymbolDisplayMiscellaneousOptions.UseSpecialTypes); - [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public ExplicitInterfaceMemberCompletionProvider() @@ -100,7 +89,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) continue; } - var memberString = member.ToMinimalDisplayString(semanticModel, namePosition, s_signatureDisplayFormat); + var memberString = CompletionSymbolDisplay.ToDisplayString(member); // Split the member string into two parts (generally the name, and the signature portion). We want // the split so that other features (like spell-checking), only look at the name portion. diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ExtensionMethodImportCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ExtensionMethodImportCompletionProvider.cs index aa87a5a012ba7..9e8bd6952bc09 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ExtensionMethodImportCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ExtensionMethodImportCompletionProvider.cs @@ -5,16 +5,12 @@ using System; using System.Collections.Immutable; using System.Composition; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Text; @@ -40,14 +36,10 @@ public override bool IsInsertionTrigger(SourceText text, int characterPosition, public override ImmutableHashSet TriggerCharacters { get; } = CompletionUtilities.CommonTriggerCharacters; - protected override ImmutableArray GetImportedNamespaces( - SyntaxNode location, - SemanticModel semanticModel, + protected override Task> GetImportedNamespacesAsync( + SyntaxContext syntaxContext, CancellationToken cancellationToken) - => ImportCompletionProviderHelper.GetImportedNamespaces(location, semanticModel); - - protected override Task CreateContextAsync(Document document, int position, CancellationToken cancellationToken) - => ImportCompletionProviderHelper.CreateContextAsync(document, position, cancellationToken); + => ImportCompletionProviderHelper.GetImportedNamespacesAsync(syntaxContext, cancellationToken); protected override bool IsFinalSemicolonOfUsingOrExtern(SyntaxNode directive, SyntaxToken token) { diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ImportCompletionProviderHelper.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ImportCompletionProviderHelper.cs index 369f67c642348..ab3df7582d3ea 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ImportCompletionProviderHelper.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ImportCompletionProviderHelper.cs @@ -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. +using System.Collections.Concurrent; using System.Collections.Immutable; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Roslyn.Utilities; @@ -15,19 +16,66 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers { internal static class ImportCompletionProviderHelper { - public static ImmutableArray GetImportedNamespaces( - SyntaxNode location, - SemanticModel semanticModel) - => semanticModel.GetUsingNamespacesInScope(location) - .SelectAsArray(namespaceSymbol => namespaceSymbol.ToDisplayString(SymbolDisplayFormats.NameFormat)); + private record class CacheEntry(DocumentId? GlobalUsingsDocumentId, Checksum GlobalUsingsDocumentChecksum, ImmutableArray GlobalUsings) + { + public static CacheEntry Default { get; } = new(null, Checksum.Null, ImmutableArray.Empty); + } + + private static readonly ConcurrentDictionary _sdkGlobalUsingsCache = new(); - public static async Task CreateContextAsync(Document document, int position, CancellationToken cancellationToken) + public static async Task> GetImportedNamespacesAsync(SyntaxContext context, CancellationToken cancellationToken) { - // Need regular semantic model because we will use it to get imported namespace symbols. Otherwise we will try to - // reach outside of the span and ended up with "node not within syntax tree" error from the speculative model. - var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - Contract.ThrowIfNull(semanticModel); - return CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken); + // The location is the containing node of the LeftToken, or the compilation unit itself if LeftToken + // indicates the beginning of the document (i.e. no parent). + var location = context.LeftToken.Parent ?? context.SyntaxTree.GetRoot(cancellationToken); + var usingsFromCurrentDocument = context.SemanticModel.GetUsingNamespacesInScope(location).SelectAsArray(GetNamespaceName); + + if (_sdkGlobalUsingsCache.TryGetValue(context.Document.Project.Id, out var cacheEntry)) + { + // Just return whatever was cached last time. It'd be very rare for this file to change. To minimize impact on completion perf, + // we'd tolerate temporarily staled results. A background task is created to refresh it if necessary. + _ = GetGlobalUsingsAsync(context.Document.Project, cacheEntry, CancellationToken.None); + return usingsFromCurrentDocument.Concat(cacheEntry.GlobalUsings); + } + else + { + // cache miss, we have to calculate it now. + var globalUsings = await GetGlobalUsingsAsync(context.Document.Project, CacheEntry.Default, cancellationToken).ConfigureAwait(false); + return usingsFromCurrentDocument.Concat(globalUsings); + } + + static async Task> GetGlobalUsingsAsync(Project project, CacheEntry cacheEntry, CancellationToken cancellationToken) + { + // Since we don't have a compiler API to easily get all global usings yet, hardcode the the name of SDK auto-generated + // global using file (which is a constant) for now as a temporary workaround. + // https://github.com/dotnet/sdk/blob/main/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateGlobalUsings.targets + var fileName = project.Name + ".GlobalUsings.g.cs"; + + var globalUsingDocument = cacheEntry.GlobalUsingsDocumentId is null + ? project.Documents.FirstOrDefault(d => d.Name.Equals(fileName)) + : await project.GetDocumentAsync(cacheEntry.GlobalUsingsDocumentId, cancellationToken: cancellationToken).ConfigureAwait(false); + + if (globalUsingDocument is null) + { + _sdkGlobalUsingsCache[project.Id] = CacheEntry.Default; + return CacheEntry.Default.GlobalUsings; + } + + // We only checksum off of the contents of the file. + var checksum = await globalUsingDocument.State.GetChecksumAsync(cancellationToken).ConfigureAwait(false); + if (checksum == cacheEntry.GlobalUsingsDocumentChecksum) + return cacheEntry.GlobalUsings; + + var root = await globalUsingDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var model = await globalUsingDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var globalUsings = model.GetUsingNamespacesInScope(root).SelectAsArray(GetNamespaceName); + + _sdkGlobalUsingsCache[project.Id] = new(globalUsingDocument.Id, checksum, globalUsings); + return globalUsings; + } + + static string GetNamespaceName(INamespaceSymbol symbol) + => symbol.ToDisplayString(SymbolDisplayFormats.NameFormat); } } } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionProvider.cs index e25e9152f33cd..f23a6b53d09a2 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionProvider.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Linq; @@ -15,11 +14,9 @@ using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers { @@ -41,14 +38,10 @@ public override bool IsInsertionTrigger(SourceText text, int characterPosition, public override ImmutableHashSet TriggerCharacters { get; } = CompletionUtilities.CommonTriggerCharacters; - protected override ImmutableArray GetImportedNamespaces( - SyntaxNode location, - SemanticModel semanticModel, + protected override Task> GetImportedNamespacesAsync( + SyntaxContext syntaxContext, CancellationToken cancellationToken) - => ImportCompletionProviderHelper.GetImportedNamespaces(location, semanticModel); - - protected override Task CreateContextAsync(Document document, int position, CancellationToken cancellationToken) - => ImportCompletionProviderHelper.CreateContextAsync(document, position, cancellationToken); + => ImportCompletionProviderHelper.GetImportedNamespacesAsync(syntaxContext, cancellationToken); protected override bool IsFinalSemicolonOfUsingOrExtern(SyntaxNode directive, SyntaxToken token) { diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs index ecf066b9f4eff..23896ed0f34fe 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs index 3c150e28420de..aff2db04346c4 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs @@ -100,7 +100,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) // Consider refining this logic to mandate completion with an argument name, if preceded by an out-of-position name // See https://github.com/dotnet/roslyn/issues/20657 - var languageVersion = ((CSharpParseOptions)document.Project.ParseOptions!).LanguageVersion; + var languageVersion = document.Project.ParseOptions!.LanguageVersion(); if (languageVersion < LanguageVersion.CSharp7_2 && token.IsMandatoryNamedParameterPosition()) { context.IsExclusive = true; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs index a994187585592..8da7c5ef788fa 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs @@ -83,10 +83,9 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) foreach (var member in members) { - const string ColonString = ":"; context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText: member.Name.EscapeIdentifier(), - displayTextSuffix: ColonString, + displayTextSuffix: "", insertionText: null, symbols: ImmutableArray.Create(member), contextPosition: context.Position, diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs index 3ffb2b6c6a304..194784d9bffde 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/SnippetCompletionProvider.cs @@ -81,12 +81,13 @@ private static async Task> GetSnippetsForDocument var syntaxFacts = document.GetRequiredLanguageService(); var semanticFacts = document.GetRequiredLanguageService(); - var leftToken = syntaxTree.GetRoot(cancellationToken).FindTokenOnLeftOfPosition(position, includeDirectives: true); + var root = syntaxTree.GetRoot(cancellationToken); + var leftToken = root.FindTokenOnLeftOfPosition(position, includeDirectives: true); var targetToken = leftToken.GetPreviousTokenIfTouchingWord(position); if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken) || syntaxTree.IsRightOfDotOrArrowOrColonColon(position, targetToken, cancellationToken) || - syntaxFacts.GetContainingTypeDeclaration(await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false), position) is EnumDeclarationSyntax) + syntaxFacts.GetContainingTypeDeclaration(root, position) is EnumDeclarationSyntax) { return ImmutableArray.Empty; } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsKeywordRecommender.cs index c0928e34b0bb9..0d8a3ce789a9a 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/AsKeywordRecommender.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs index 1e96e0226298f..b525ac7ca9968 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/InKeywordRecommender.cs @@ -28,7 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context IsValidContextInJoinClause(context, cancellationToken) || IsInParameterModifierContext(position, context) || syntaxTree.IsAnonymousMethodParameterModifierContext(position, context.LeftToken) || - syntaxTree.IsPossibleLambdaParameterModifierContext(position, context.LeftToken) || + syntaxTree.IsPossibleLambdaParameterModifierContext(position, context.LeftToken, cancellationToken) || context.TargetToken.IsConstructorOrMethodParameterArgumentContext() || context.TargetToken.IsTypeParameterVarianceContext(); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OutKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OutKeywordRecommender.cs index c5ed926cfe23f..53db60bf68688 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OutKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OutKeywordRecommender.cs @@ -20,12 +20,11 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context { var syntaxTree = context.SyntaxTree; - // TODO(cyrusn): lambda/anon methods can have out/ref parameters return context.TargetToken.IsTypeParameterVarianceContext() || IsOutParameterModifierContext(position, context) || syntaxTree.IsAnonymousMethodParameterModifierContext(position, context.LeftToken) || - syntaxTree.IsPossibleLambdaParameterModifierContext(position, context.LeftToken) || + syntaxTree.IsPossibleLambdaParameterModifierContext(position, context.LeftToken, cancellationToken) || context.TargetToken.IsConstructorOrMethodParameterArgumentContext() || context.TargetToken.IsXmlCrefParameterModifierContext(); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RefKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RefKeywordRecommender.cs index 09d24f5ede379..846997c6a3e8f 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RefKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RefKeywordRecommender.cs @@ -82,9 +82,9 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context var syntaxTree = context.SyntaxTree; return IsRefParameterModifierContext(position, context) || - syntaxTree.IsAnonymousMethodParameterModifierContext(position, context.LeftToken) || IsValidContextForType(context, cancellationToken) || - syntaxTree.IsPossibleLambdaParameterModifierContext(position, context.LeftToken) || + syntaxTree.IsAnonymousMethodParameterModifierContext(position, context.LeftToken) || + syntaxTree.IsPossibleLambdaParameterModifierContext(position, context.LeftToken, cancellationToken) || context.TargetToken.IsConstructorOrMethodParameterArgumentContext() || context.TargetToken.IsXmlCrefParameterModifierContext() || IsValidNewByRefContext(syntaxTree, position, context, cancellationToken); diff --git a/src/Features/CSharp/Portable/Completion/Providers/ContextVariableArgumentProvider.cs b/src/Features/CSharp/Portable/Completion/Providers/ContextVariableArgumentProvider.cs index 7666faf54b5ef..8fd8b96510e1f 100644 --- a/src/Features/CSharp/Portable/Completion/Providers/ContextVariableArgumentProvider.cs +++ b/src/Features/CSharp/Portable/Completion/Providers/ContextVariableArgumentProvider.cs @@ -4,7 +4,10 @@ using System; using System.Composition; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers @@ -19,5 +22,33 @@ internal sealed class ContextVariableArgumentProvider : AbstractContextVariableA public ContextVariableArgumentProvider() { } + + protected override string ThisOrMeKeyword => SyntaxFacts.GetText(SyntaxKind.ThisKeyword); + + protected override bool IsInstanceContext(SyntaxTree syntaxTree, SyntaxToken targetToken, SemanticModel semanticModel, CancellationToken cancellationToken) + => syntaxTree.IsInstanceContext(targetToken, semanticModel, cancellationToken); + + public override async Task ProvideArgumentAsync(ArgumentContext context) + { + await base.ProvideArgumentAsync(context).ConfigureAwait(false); + if (context.DefaultValue is not null) + { + switch (context.Parameter.RefKind) + { + case RefKind.Ref: + context.DefaultValue = "ref " + context.DefaultValue; + break; + + case RefKind.Out: + context.DefaultValue = "out " + context.DefaultValue; + break; + + case RefKind.In: + case RefKind.None: + default: + break; + } + } + } } } diff --git a/src/Features/CSharp/Portable/Completion/Providers/DefaultArgumentProvider.cs b/src/Features/CSharp/Portable/Completion/Providers/DefaultArgumentProvider.cs index 242ffc9266704..87fcc97555f15 100644 --- a/src/Features/CSharp/Portable/Completion/Providers/DefaultArgumentProvider.cs +++ b/src/Features/CSharp/Portable/Completion/Providers/DefaultArgumentProvider.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers { [ExportArgumentProvider(nameof(DefaultArgumentProvider), LanguageNames.CSharp)] - [ExtensionOrder(After = nameof(ContextVariableArgumentProvider))] + [ExtensionOrder(After = nameof(OutVariableArgumentProvider))] [Shared] internal sealed class DefaultArgumentProvider : AbstractDefaultArgumentProvider { diff --git a/src/Features/CSharp/Portable/Completion/Providers/OutVariableArgumentProvider.cs b/src/Features/CSharp/Portable/Completion/Providers/OutVariableArgumentProvider.cs new file mode 100644 index 0000000000000..3ebc6db455ed4 --- /dev/null +++ b/src/Features/CSharp/Portable/Completion/Providers/OutVariableArgumentProvider.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Tasks; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers +{ + [ExportArgumentProvider(nameof(OutVariableArgumentProvider), LanguageNames.CSharp)] + [ExtensionOrder(After = nameof(ContextVariableArgumentProvider))] + [Shared] + internal sealed class OutVariableArgumentProvider : ArgumentProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public OutVariableArgumentProvider() + { + } + + public override Task ProvideArgumentAsync(ArgumentContext context) + { + if (context.PreviousValue is not null) + { + // This argument provider does not attempt to replace arguments already in code. + return Task.CompletedTask; + } + + if (context.Parameter.RefKind != RefKind.Out) + { + // This argument provider only considers 'out' parameters. + return Task.CompletedTask; + } + + // Since tihs provider runs after ContextVariableArgumentProvider, we know there is no suitable target in + // the current context. Instead, offer to declare a new variable. + var name = context.Parameter.Name; + if (SyntaxFacts.GetKeywordKind(name) != SyntaxKind.None + || SyntaxFacts.GetContextualKeywordKind(name) != SyntaxKind.None) + { + name = "@" + name; + } + + var syntax = SyntaxFactory.Argument( + nameColon: null, + refKindKeyword: SyntaxFactory.Token(SyntaxKind.OutKeyword), + SyntaxFactory.DeclarationExpression( + type: SyntaxFactory.IdentifierName("var"), + designation: SyntaxFactory.SingleVariableDesignation(SyntaxFactory.Identifier( + SyntaxFactory.TriviaList(), + contextualKind: SyntaxKind.None, + text: name, + valueText: context.Parameter.Name, + SyntaxFactory.TriviaList())))); + + context.DefaultValue = syntax.NormalizeWhitespace().ToFullString(); + return Task.CompletedTask; + } + } +} diff --git a/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs index c42c8b9fd343f..c837c80b34065 100644 --- a/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs @@ -12,12 +12,12 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.ConvertAutoPropertyToFullProperty; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; 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.Shared.Utilities; using static Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles.SymbolSpecification; @@ -25,7 +25,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ConvertAutoPropertyToFullProperty { [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.ConvertAutoPropertyToFullProperty), Shared] - internal class CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider : AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider + internal class CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider : AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] @@ -46,7 +46,7 @@ internal override async Task GetFieldNameAsync(Document document, IPrope } internal override (SyntaxNode newGetAccessor, SyntaxNode newSetAccessor) GetNewAccessors( - DocumentOptionSet options, SyntaxNode property, + CSharpCodeGenerationPreferences preferences, SyntaxNode property, string fieldName, SyntaxGenerator generator) { // C# might have trivia with the accessors that needs to be preserved. @@ -55,7 +55,7 @@ internal override (SyntaxNode newGetAccessor, SyntaxNode newSetAccessor) GetNewA var (getAccessor, setAccessor) = GetExistingAccessors(accessorListSyntax); var getAccessorStatement = generator.ReturnStatement(generator.IdentifierName(fieldName)); - var newGetter = GetUpdatedAccessor(options, getAccessor, getAccessorStatement); + var newGetter = GetUpdatedAccessor(preferences, getAccessor, getAccessorStatement); SyntaxNode newSetter = null; if (setAccessor != null) @@ -63,7 +63,7 @@ internal override (SyntaxNode newGetAccessor, SyntaxNode newSetAccessor) GetNewA var setAccessorStatement = generator.ExpressionStatement(generator.AssignmentStatement( generator.IdentifierName(fieldName), generator.IdentifierName("value"))); - newSetter = GetUpdatedAccessor(options, setAccessor, setAccessorStatement); + newSetter = GetUpdatedAccessor(preferences, setAccessor, setAccessorStatement); } return (newGetAccessor: newGetter, newSetAccessor: newSetter); @@ -75,20 +75,20 @@ private static (AccessorDeclarationSyntax getAccessor, AccessorDeclarationSyntax accessorListSyntax.Accessors.FirstOrDefault(a => a.IsKind(SyntaxKind.SetAccessorDeclaration) || a.IsKind(SyntaxKind.InitAccessorDeclaration))); - private static SyntaxNode GetUpdatedAccessor(DocumentOptionSet options, + private static SyntaxNode GetUpdatedAccessor(CSharpCodeGenerationPreferences preferences, SyntaxNode accessor, SyntaxNode statement) { var newAccessor = AddStatement(accessor, statement); var accessorDeclarationSyntax = (AccessorDeclarationSyntax)newAccessor; - var preference = GetAccessorExpressionBodyPreference(options); + var preference = preferences.PreferExpressionBodiedAccessors; if (preference == ExpressionBodyPreference.Never) { return accessorDeclarationSyntax.WithSemicolonToken(default); } if (!accessorDeclarationSyntax.Body.TryConvertToArrowExpressionBody( - accessorDeclarationSyntax.Kind(), accessor.SyntaxTree.Options, preference, + accessorDeclarationSyntax.Kind(), preferences.LanguageVersion, preference, out var arrowExpression, out _)) { return accessorDeclarationSyntax.WithSemicolonToken(default); @@ -113,11 +113,11 @@ internal static SyntaxNode AddStatement(SyntaxNode accessor, SyntaxNode statemen } internal override SyntaxNode ConvertPropertyToExpressionBodyIfDesired( - DocumentOptionSet options, SyntaxNode property) + CSharpCodeGenerationPreferences preferences, SyntaxNode property) { var propertyDeclaration = (PropertyDeclarationSyntax)property; - var preference = GetPropertyExpressionBodyPreference(options); + var preference = preferences.PreferExpressionBodiedProperties; if (preference == ExpressionBodyPreference.Never) { return propertyDeclaration.WithSemicolonToken(default); @@ -139,12 +139,6 @@ internal override SyntaxNode ConvertPropertyToExpressionBodyIfDesired( return propertyDeclaration.WithSemicolonToken(default); } - internal static ExpressionBodyPreference GetAccessorExpressionBodyPreference(DocumentOptionSet options) - => options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors).Value; - - internal static ExpressionBodyPreference GetPropertyExpressionBodyPreference(DocumentOptionSet options) - => options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties).Value; - internal override SyntaxNode GetTypeBlock(SyntaxNode syntaxNode) => syntaxNode; diff --git a/src/Features/CSharp/Portable/ConvertForEachToFor/CSharpConvertForEachToForCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertForEachToFor/CSharpConvertForEachToForCodeRefactoringProvider.cs index 8a0c865552593..51dbc9cdcfa5b 100644 --- a/src/Features/CSharp/Portable/ConvertForEachToFor/CSharpConvertForEachToForCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertForEachToFor/CSharpConvertForEachToForCodeRefactoringProvider.cs @@ -64,9 +64,9 @@ protected override void ConvertToForStatement( var collectionVariable = GetCollectionVariableName( model, generator, foreachInfo, foreachCollectionExpression, cancellationToken); - var typeSymbol = foreachInfo.RequireExplicitCastInterface - ? foreachInfo.ExplicitCastInterface - : model.GetTypeInfo(foreachCollectionExpression, cancellationToken).Type ?? model.Compilation.GetSpecialType(SpecialType.System_Object); + var typeSymbol = foreachInfo.ExplicitCastInterface ?? + model.GetTypeInfo(foreachCollectionExpression, cancellationToken).Type ?? + model.Compilation.GetSpecialType(SpecialType.System_Object); var collectionStatementType = typeSymbol.GenerateTypeSyntax(); diff --git a/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.cs index 3b9f09193ebc3..f28d11846f910 100644 --- a/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertIfToSwitch/CSharpConvertIfToSwitchCodeRefactoringProvider.cs @@ -6,6 +6,7 @@ using System.Composition; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.ConvertIfToSwitch; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; @@ -30,11 +31,11 @@ public override string GetTitle(bool forSwitchExpression) public override Analyzer CreateAnalyzer(ISyntaxFacts syntaxFacts, ParseOptions options) { - var version = ((CSharpParseOptions)options).LanguageVersion; + var version = options.LanguageVersion(); var features = (version >= LanguageVersion.CSharp7 ? Feature.SourcePattern | Feature.IsTypePattern | Feature.CaseGuard : 0) | (version >= LanguageVersion.CSharp8 ? Feature.SwitchExpression : 0) | - (version.IsCSharp9OrAbove() ? Feature.RelationalPattern | Feature.OrPattern | Feature.AndPattern | Feature.TypePattern : 0); + (version >= LanguageVersion.CSharp9 ? Feature.RelationalPattern | Feature.OrPattern | Feature.AndPattern | Feature.TypePattern : 0); return new CSharpAnalyzer(syntaxFacts, features); } } diff --git a/src/Features/CSharp/Portable/ConvertToInterpolatedString/CSharpConvertConcatenationToInterpolatedStringRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToInterpolatedString/CSharpConvertConcatenationToInterpolatedStringRefactoringProvider.cs index 5506f1908e093..50be3052cd778 100644 --- a/src/Features/CSharp/Portable/ConvertToInterpolatedString/CSharpConvertConcatenationToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertToInterpolatedString/CSharpConvertConcatenationToInterpolatedStringRefactoringProvider.cs @@ -6,6 +6,7 @@ using System.Composition; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.ConvertToInterpolatedString; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; @@ -23,7 +24,7 @@ public CSharpConvertConcatenationToInterpolatedStringRefactoringProvider() } protected override bool SupportsConstantInterpolatedStrings(Document document) - => ((CSharpParseOptions)document.Project.ParseOptions!).LanguageVersion.HasConstantInterpolatedStrings(); + => document.Project.ParseOptions!.LanguageVersion().HasConstantInterpolatedStrings(); protected override string GetTextWithoutQuotes(string text, bool isVerbatim, bool isCharacterLiteral) => isVerbatim diff --git a/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs new file mode 100644 index 0000000000000..f65ebc0594a6d --- /dev/null +++ b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs @@ -0,0 +1,257 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.CodeActions; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.ConvertToRawString +{ + using static ConvertToRawStringHelpers; + + [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.ConvertToRawString), Shared] + internal class ConvertRegularStringToRawStringCodeRefactoringProvider : CodeRefactoringProvider + { + private enum ConvertToRawKind + { + SingleLine, + MultiLine, + MultiLineIndented, + } + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public ConvertRegularStringToRawStringCodeRefactoringProvider() + { + } + + public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) + { + var (document, span, cancellationToken) = context; + + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var token = root.FindToken(span.Start); + if (!context.Span.IntersectsWith(token.Span)) + return; + + if (token.Kind() != SyntaxKind.StringLiteralToken) + return; + + // Can't convert a string literal in a directive to a raw string. + if (IsInDirective(token.Parent)) + return; + + var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); + + // TODO(cyrusn): Should we offer this on empty strings... seems undesirable as you'd end with a gigantic + // three line alternative over just "" + if (characters.IsDefaultOrEmpty) + return; + + // Ensure that all characters in the string are those we can convert. + if (!characters.All(static ch => CanConvert(ch))) + return; + + // If we have escaped quotes in the string, then this is a good option to bubble up as something to convert + // to a raw string. Otherwise, still offer this refactoring, but at low priority as the user may be + // invoking this on lots of strings that they have no interest in converting. + var priority = AllEscapesAreQuotes(characters) ? CodeActionPriority.Medium : CodeActionPriority.Low; + + var canBeSingleLine = CanBeSingleLine(characters); + + if (canBeSingleLine) + { + context.RegisterRefactoring( + new MyCodeAction( + CSharpFeaturesResources.Convert_to_raw_string, + c => UpdateDocumentAsync(document, span, ConvertToRawKind.SingleLine, c), + nameof(CSharpFeaturesResources.Convert_to_raw_string) + "-" + ConvertToRawKind.SingleLine, + priority), + token.Span); + } + else + { + var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(true); + sourceText.GetLineAndOffset(token.SpanStart, out _, out var lineOffset); + + context.RegisterRefactoring( + new MyCodeAction( + CSharpFeaturesResources.Convert_to_raw_string, + c => UpdateDocumentAsync(document, span, ConvertToRawKind.MultiLineIndented, c), + nameof(CSharpFeaturesResources.Convert_to_raw_string), + priority), + token.Span); + + if (lineOffset > 0) + { + context.RegisterRefactoring( + new MyCodeAction( + CSharpFeaturesResources.Convert_to_raw_string_no_indent, + c => UpdateDocumentAsync(document, span, ConvertToRawKind.MultiLine, c), + nameof(CSharpFeaturesResources.Convert_to_raw_string_no_indent), + priority), + token.Span); + } + } + } + + private static async Task UpdateDocumentAsync( + Document document, TextSpan span, ConvertToRawKind kind, CancellationToken cancellationToken) + { + var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var newLine = options.GetOption(FormattingOptions.NewLine); + + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var token = root.FindToken(span.Start); + Contract.ThrowIfFalse(span.IntersectsWith(token.Span)); + Contract.ThrowIfFalse(token.Kind() == SyntaxKind.StringLiteralToken); + + var replacement = GetReplacementToken(document, token, kind, newLine, cancellationToken); + return document.WithSyntaxRoot(root.ReplaceToken(token, replacement)); + } + + private static SyntaxToken GetReplacementToken( + Document document, + SyntaxToken token, + ConvertToRawKind kind, + string newLine, + CancellationToken cancellationToken) + { + return kind switch + { + ConvertToRawKind.SingleLine => ConvertToSingleLineRawString(token), + ConvertToRawKind.MultiLine => ConvertToMultiLineRawString(token, newLine), + ConvertToRawKind.MultiLineIndented => ConvertToMultiLineRawIndentedString(document, token, newLine, cancellationToken), + _ => throw ExceptionUtilities.UnexpectedValue(kind), + }; + } + + private static SyntaxToken ConvertToMultiLineRawIndentedString(Document document, SyntaxToken token, string newLine, CancellationToken cancellationToken) + { + var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); + Contract.ThrowIfTrue(characters.IsDefaultOrEmpty); + + // 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); + var indentation = token.GetPreferredIndentation(document, cancellationToken); + + using var _ = PooledStringBuilder.GetInstance(out var builder); + + builder.Append('"', quoteDelimeterCount); + builder.Append(newLine); + + var atStartOfLine = true; + for (int i = 0, n = characters.Length; i < n; i++) + { + var ch = characters[i]; + if (IsNewLine(ch)) + { + ch.AppendTo(builder); + atStartOfLine = true; + continue; + } + + if (atStartOfLine) + { + builder.Append(indentation); + atStartOfLine = false; + } + + ch.AppendTo(builder); + } + + builder.Append(newLine); + builder.Append(indentation); + builder.Append('"', quoteDelimeterCount); + + return SyntaxFactory.Token( + token.LeadingTrivia, + SyntaxKind.MultiLineRawStringLiteralToken, + builder.ToString(), + characters.CreateString(), + token.TrailingTrivia); + } + + private static SyntaxToken ConvertToMultiLineRawString(SyntaxToken token, string newLine) + { + var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); + Contract.ThrowIfTrue(characters.IsDefaultOrEmpty); + + // 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); + + using var _ = PooledStringBuilder.GetInstance(out var builder); + + builder.Append('"', quoteDelimeterCount); + builder.Append(newLine); + + foreach (var ch in characters) + ch.AppendTo(builder); + + builder.Append(newLine); + builder.Append('"', quoteDelimeterCount); + + return SyntaxFactory.Token( + token.LeadingTrivia, + SyntaxKind.MultiLineRawStringLiteralToken, + builder.ToString(), + characters.CreateString(), + token.TrailingTrivia); + } + + private static SyntaxToken ConvertToSingleLineRawString(SyntaxToken token) + { + var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); + Contract.ThrowIfTrue(characters.IsDefaultOrEmpty); + + // 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); + + using var _ = PooledStringBuilder.GetInstance(out var builder); + + builder.Append('"', quoteDelimeterCount); + + foreach (var ch in characters) + ch.AppendTo(builder); + + builder.Append('"', quoteDelimeterCount); + + return SyntaxFactory.Token( + token.LeadingTrivia, + SyntaxKind.SingleLineRawStringLiteralToken, + builder.ToString(), + characters.CreateString(), + token.TrailingTrivia); + } + + private class MyCodeAction : CodeAction.DocumentChangeAction + { + internal override CodeActionPriority Priority { get; } + + public MyCodeAction( + string title, + Func> createChangedDocument, + string equivalenceKey, + CodeActionPriority priority) + : base(title, createChangedDocument, equivalenceKey) + { + Priority = priority; + } + } + } +} diff --git a/src/Features/CSharp/Portable/ConvertToRawString/ConvertToRawStringHelpers.cs b/src/Features/CSharp/Portable/ConvertToRawString/ConvertToRawStringHelpers.cs new file mode 100644 index 0000000000000..fed44e78e66a8 --- /dev/null +++ b/src/Features/CSharp/Portable/ConvertToRawString/ConvertToRawStringHelpers.cs @@ -0,0 +1,112 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Text; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.CSharp.ConvertToRawString +{ + internal static class ConvertToRawStringHelpers + { + public static bool CanBeSingleLine(VirtualCharSequence characters) + { + // Single line raw strings cannot start/end with quote. + if (characters.First().Rune.Value == '"' || + characters.Last().Rune.Value == '"') + { + return false; + } + + // a single line raw string cannot contain a newline. + if (characters.Any(static ch => IsNewLine(ch))) + return false; + + return true; + } + + public static bool IsNewLine(VirtualChar ch) + => ch.Rune.Utf16SequenceLength == 1 && SyntaxFacts.IsNewLine((char)ch.Value); + + public static bool AllEscapesAreQuotes(VirtualCharSequence sequence) + => AllEscapesAre(sequence, static ch => ch.Value == '"'); + + private static bool AllEscapesAre(VirtualCharSequence sequence, Func predicate) + { + var hasEscape = false; + + foreach (var ch in sequence) + { + if (ch.Span.Length > 1) + { + hasEscape = true; + if (!predicate(ch)) + return false; + } + } + + return hasEscape; + } + + public static bool IsInDirective(SyntaxNode? node) + { + while (node != null) + { + if (node is DirectiveTriviaSyntax) + return true; + + node = node.GetParent(ascendOutOfTrivia: true); + } + + return false; + } + + public static bool CanConvert(VirtualChar ch) + { + // Don't bother with unpaired surrogates. This is just a legacy language corner case that we don't care to + // even try having support for. + if (ch.SurrogateChar != 0) + return false; + + // Can't ever encode a null value directly in a c# file as our lexer/parser/text apis will stop righ there. + if (ch.Rune.Value == 0) + return false; + + // Check if we have an escaped character in the original string. + if (ch.Span.Length > 1) + { + // An escaped newline is fine to convert (to a multi-line raw string). + if (IsNewLine(ch)) + return true; + + // Control/formatting unicode escapes should stay as escapes. The user code will just be enormously + // difficult to read/reason about if we convert those to the actual corresponding non-escaped chars. + var category = Rune.GetUnicodeCategory(ch.Rune); + if (category is UnicodeCategory.Format or UnicodeCategory.Control) + return false; + } + + return true; + } + + public static int GetLongestQuoteSequence(VirtualCharSequence characters) + { + var longestQuoteSequence = 0; + for (int i = 0, n = characters.Length; i < n;) + { + var j = i; + while (j < n && characters[j] == '"') + j++; + + longestQuoteSequence = Math.Max(longestQuoteSequence, j - i); + i = j + 1; + } + + return longestQuoteSequence; + } + } +} diff --git a/src/Features/CSharp/Portable/Debugging/CSharpProximityExpressionsService.Worker.cs b/src/Features/CSharp/Portable/Debugging/CSharpProximityExpressionsService.Worker.cs index 19161e53e41fb..b9c912c5d5e18 100644 --- a/src/Features/CSharp/Portable/Debugging/CSharpProximityExpressionsService.Worker.cs +++ b/src/Features/CSharp/Portable/Debugging/CSharpProximityExpressionsService.Worker.cs @@ -70,7 +70,7 @@ private void AddThisExpression() { // If it's an instance member, then also add "this". var memberDeclaration = _parentStatement.GetAncestorOrThis(); - if (!memberDeclaration.GetModifiers().Any(SyntaxKind.StaticKeyword)) + if (!memberDeclaration.IsKind(SyntaxKind.GlobalStatement) && !memberDeclaration.GetModifiers().Any(SyntaxKind.StaticKeyword)) { _expressions.Add("this"); } @@ -119,6 +119,12 @@ private void AddMethodParameters() var parameterList = ((MemberDeclarationSyntax)block.Parent).GetParameterList(); AddParameters(parameterList); } + else if (block is null + && _parentStatement.Parent is GlobalStatementSyntax { Parent: CompilationUnitSyntax compilationUnit } globalStatement + && compilationUnit.Members.FirstOrDefault() == globalStatement) + { + _expressions.Add("args"); + } } private void AddIndexerParameters() diff --git a/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs b/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs index 80490248ed78b..478c975007d3d 100644 --- a/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs +++ b/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs @@ -94,9 +94,6 @@ protected override int GetPrecedingDocumentationCommentCount(MemberDeclarationSy return count; } - protected override bool IsMemberDeclaration(MemberDeclarationSyntax member) - => true; - protected override List GetDocumentationCommentStubLines(MemberDeclarationSyntax member) { var list = new List diff --git a/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpEmbeddedLanguageFeaturesProvider.cs b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpEmbeddedLanguageFeaturesProvider.cs index 2509370c46707..629c73061c9ee 100644 --- a/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpEmbeddedLanguageFeaturesProvider.cs +++ b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpEmbeddedLanguageFeaturesProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.LanguageServices; @@ -23,7 +21,7 @@ public CSharpEmbeddedLanguageFeaturesProvider() { } - internal override string EscapeText(string text, SyntaxToken token) + public override string EscapeText(string text, SyntaxToken token) => EmbeddedLanguageUtilities.EscapeText(text, token); } } diff --git a/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpJsonDetectionAnalyzer.cs b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpJsonDetectionAnalyzer.cs new file mode 100644 index 0000000000000..a980c2de38478 --- /dev/null +++ b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpJsonDetectionAnalyzer.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; + +namespace Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + internal class CSharpJsonDetectionAnalyzer : AbstractJsonDetectionAnalyzer + { + public CSharpJsonDetectionAnalyzer() + : base(CSharpEmbeddedLanguagesProvider.Info) + { + } + } +} diff --git a/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpJsonDetectionCodeFixProvider.cs b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpJsonDetectionCodeFixProvider.cs new file mode 100644 index 0000000000000..52f45201f2206 --- /dev/null +++ b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpJsonDetectionCodeFixProvider.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.Features.EmbeddedLanguages; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.JsonDetection), Shared] + internal class CSharpJsonDetectionCodeFixProvider : AbstractJsonDetectionCodeFixProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpJsonDetectionCodeFixProvider() + : base(CSharpEmbeddedLanguagesProvider.Info) + { + } + + protected override void AddComment(SyntaxEditor editor, SyntaxToken stringLiteral, string commentContents) + => EmbeddedLanguageUtilities.AddComment(editor, stringLiteral, commentContents); + } +} diff --git a/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpJsonDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpJsonDiagnosticAnalyzer.cs new file mode 100644 index 0000000000000..675af4912ac47 --- /dev/null +++ b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpJsonDiagnosticAnalyzer.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; + +namespace Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + internal class CSharpJsonDiagnosticAnalyzer : AbstractJsonDiagnosticAnalyzer + { + public CSharpJsonDiagnosticAnalyzer() + : base(CSharpEmbeddedLanguagesProvider.Info) + { + } + } +} diff --git a/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpRegexDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpRegexDiagnosticAnalyzer.cs index 939ba8f8e405f..4058db4658589 100644 --- a/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpRegexDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/EmbeddedLanguages/CSharpRegexDiagnosticAnalyzer.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.LanguageServices; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; namespace Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages { diff --git a/src/Features/CSharp/Portable/EmbeddedLanguages/EmbeddedLanguageUtilities.cs b/src/Features/CSharp/Portable/EmbeddedLanguages/EmbeddedLanguageUtilities.cs index 11397445fd15d..e82e6a5995795 100644 --- a/src/Features/CSharp/Portable/EmbeddedLanguages/EmbeddedLanguageUtilities.cs +++ b/src/Features/CSharp/Portable/EmbeddedLanguages/EmbeddedLanguageUtilities.cs @@ -5,11 +5,22 @@ #nullable disable using System.Diagnostics; +using Microsoft.CodeAnalysis.Editing; namespace Microsoft.CodeAnalysis.CSharp.Features.EmbeddedLanguages { internal static class EmbeddedLanguageUtilities { + internal static void AddComment(SyntaxEditor editor, SyntaxToken stringLiteral, string commentContents) + { + var triviaList = SyntaxFactory.TriviaList( + SyntaxFactory.Comment($"/*{commentContents}*/"), + SyntaxFactory.ElasticSpace); + var newStringLiteral = stringLiteral.WithLeadingTrivia( + stringLiteral.LeadingTrivia.AddRange(triviaList)); + editor.ReplaceNode(stringLiteral.Parent, stringLiteral.Parent.ReplaceToken(stringLiteral, newStringLiteral)); + } + public static string EscapeText(string text, SyntaxToken token) { // This function is called when Completion needs to escape something its going to diff --git a/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs b/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs index 4bef21b437383..5bbec277915c9 100644 --- a/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs +++ b/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs @@ -106,7 +106,7 @@ protected override async Task RewriteFieldNameAndAccessibilityAsync( field.ConstantValue, declarator.Initializer)); - var withField = await codeGenService.AddFieldAsync(document.Project.Solution, field.ContainingType, fieldToAdd, new CodeGenerationOptions(), cancellationToken).ConfigureAwait(false); + var withField = await codeGenService.AddFieldAsync(document.Project.Solution, field.ContainingType, fieldToAdd, CodeGenerationContext.Default, cancellationToken).ConfigureAwait(false); root = await withField.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); declarator = root.GetAnnotatedNodes(tempAnnotation).First(); diff --git a/src/Features/CSharp/Portable/ExternalAccess/Pythia/PythiaSignatureHelpProvider.cs b/src/Features/CSharp/Portable/ExternalAccess/Pythia/PythiaSignatureHelpProvider.cs index df31038cc9e84..13891692fadbd 100644 --- a/src/Features/CSharp/Portable/ExternalAccess/Pythia/PythiaSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/ExternalAccess/Pythia/PythiaSignatureHelpProvider.cs @@ -35,10 +35,11 @@ public PythiaSignatureHelpProvider(Lazy item.UnderlyingObject), selectedItemIndex); } } diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs index e64342081ccbe..0d4390d3bb316 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs @@ -177,7 +177,7 @@ selectedNode is FieldDeclarationSyntax || } protected override bool ShouldLocalFunctionCaptureParameter(SyntaxNode node) - => ((CSharpParseOptions)node.SyntaxTree.Options).LanguageVersion < LanguageVersion.CSharp8; + => node.SyntaxTree.Options.LanguageVersion() < LanguageVersion.CSharp8; private static bool IsExpressionBodiedMember(SyntaxNode node) => node is MemberDeclarationSyntax member && member.GetExpressionBody() != null; @@ -230,7 +230,7 @@ private DeclarationModifiers CreateMethodModifiers() var isReadOnly = AnalyzerResult.ShouldBeReadOnly; // Static local functions are only supported in C# 8.0 and later - var languageVersion = ((CSharpParseOptions)SemanticDocument.SyntaxTree.Options).LanguageVersion; + var languageVersion = SemanticDocument.SyntaxTree.Options.LanguageVersion(); if (LocalFunction && (!Options.GetOption(CSharpCodeStyleOptions.PreferStaticLocalFunction).Value || languageVersion < LanguageVersion.CSharp8)) { diff --git a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs index e28e9714f4f1c..c0256ecb8e2c2 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpAccessibilityModifiersNewDocumentFormattingProvider.cs @@ -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); + var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); var service = document.GetRequiredLanguageService(); diff --git a/src/Features/CSharp/Portable/Formatting/CSharpFormattingInteractionService.cs b/src/Features/CSharp/Portable/Formatting/CSharpFormattingInteractionService.cs index 366877442ed69..5f292e5ad6d07 100644 --- a/src/Features/CSharp/Portable/Formatting/CSharpFormattingInteractionService.cs +++ b/src/Features/CSharp/Portable/Formatting/CSharpFormattingInteractionService.cs @@ -44,15 +44,9 @@ public CSharpFormattingInteractionService() public bool SupportsFormatSelection => true; public bool SupportsFormatOnReturn => false; - public bool SupportsFormattingOnTypedCharacter(Document document, char ch) + public bool SupportsFormattingOnTypedCharacter(Document document, AutoFormattingOptions options, char ch) { - // Performance: This method checks several options to determine if we should do smart - // indent, none of which are controlled by editorconfig. Instead of calling - // document.GetOptionsAsync we can use the Workspace's global options and thus save the - // work of attempting to read in the editorconfig file. - var options = document.Project.Solution.Workspace.Options; - - var smartIndentOn = options.GetOption(FormattingOptions.SmartIndent, LanguageNames.CSharp) == FormattingOptions.IndentStyle.Smart; + var smartIndentOn = options.IndentStyle == FormattingOptions.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 @@ -69,18 +63,18 @@ public bool SupportsFormattingOnTypedCharacter(Document document, char ch) } // If format-on-typing is not on, then we don't support formatting on any other characters. - var autoFormattingOnTyping = options.GetOption(FormattingBehaviorOptions.AutoFormattingOnTyping, LanguageNames.CSharp); + var autoFormattingOnTyping = options.FormatOnTyping; if (!autoFormattingOnTyping) { return false; } - if (ch == '}' && !options.GetOption(BraceCompletionOptions.AutoFormattingOnCloseBrace, LanguageNames.CSharp)) + if (ch == '}' && !options.FormatOnCloseBrace) { return false; } - if (ch == ';' && !options.GetOption(FormattingBehaviorOptions.AutoFormattingOnSemicolon, LanguageNames.CSharp)) + if (ch == ';' && !options.FormatOnSemicolon) { return false; } @@ -103,16 +97,15 @@ public async Task> GetFormattingChangesAsync( var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var span = textSpan ?? new TextSpan(0, root.FullSpan.Length); var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span); - var options = documentOptions; - if (options == null) + if (documentOptions == null) { var inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService(); - options = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat: true, cancellationToken: cancellationToken).ConfigureAwait(false); + documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat: true, cancellationToken: cancellationToken).ConfigureAwait(false); } - return Formatter.GetFormattedTextChanges(root, - SpecializedCollections.SingletonEnumerable(formattingSpan), - document.Project.Solution.Workspace, options, cancellationToken).ToImmutableArray(); + var services = document.Project.Solution.Workspace.Services; + var formattingOptions = SyntaxFormattingOptions.Create(documentOptions, services, document.Project.Language); + return Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, formattingOptions, cancellationToken).ToImmutableArray(); } public async Task> GetFormattingChangesOnPasteAsync( @@ -124,23 +117,20 @@ public async Task> GetFormattingChangesOnPasteAsync( var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, textSpan); - var service = document.GetLanguageService(); - if (service == null) - { - return ImmutableArray.Empty; - } + var service = document.GetRequiredLanguageService(); var rules = new List() { new PasteFormattingRule() }; rules.AddRange(service.GetDefaultFormattingRules()); - var options = documentOptions; - if (options == null) + if (documentOptions == null) { var inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService(); - options = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat: false, cancellationToken: cancellationToken).ConfigureAwait(false); + documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat: false, cancellationToken: cancellationToken).ConfigureAwait(false); } - return Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), document.Project.Solution.Workspace, options, rules, cancellationToken).ToImmutableArray(); + var formattingOptions = SyntaxFormattingOptions.Create(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language); + var result = service.GetFormattingResult(root, SpecializedCollections.SingletonEnumerable(formattingSpan), formattingOptions, rules, cancellationToken); + return result.GetTextChanges(cancellationToken).ToImmutableArray(); } private static IEnumerable GetFormattingRules(Document document, int position, SyntaxToken tokenBeforeCaret) @@ -218,13 +208,16 @@ public async Task> GetFormattingChangesAsync( return ImmutableArray.Empty; } - var options = documentOptions; - if (options == null) + var services = document.Project.Solution.Workspace.Services; + + if (documentOptions == null) { - var inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService(); - options = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat: false, cancellationToken: cancellationToken).ConfigureAwait(false); + var inferredIndentationService = services.GetRequiredService(); + documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat: false, cancellationToken: cancellationToken).ConfigureAwait(false); } + var options = IndentationOptions.From(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language); + // Do not attempt to format on open/close brace if autoformat on close brace feature is // off, instead just smart indent. // @@ -254,8 +247,8 @@ public async Task> GetFormattingChangesAsync( // However, we won't touch any of the other code in that block, unlike if we were // formatting. var onlySmartIndent = - (token.IsKind(SyntaxKind.CloseBraceToken) && OnlySmartIndentCloseBrace(options)) || - (token.IsKind(SyntaxKind.OpenBraceToken) && OnlySmartIndentOpenBrace(options)); + (token.IsKind(SyntaxKind.CloseBraceToken) && OnlySmartIndentCloseBrace(options.AutoFormattingOptions)) || + (token.IsKind(SyntaxKind.OpenBraceToken) && OnlySmartIndentOpenBrace(options.AutoFormattingOptions)); if (onlySmartIndent) { @@ -276,20 +269,19 @@ public async Task> GetFormattingChangesAsync( return (await FormatTokenAsync(document, options, token, formattingRules, cancellationToken).ConfigureAwait(false)).ToImmutableArray(); } - private static bool OnlySmartIndentCloseBrace(DocumentOptionSet options) + private static bool OnlySmartIndentCloseBrace(in AutoFormattingOptions options) { // User does not want auto-formatting (either in general, or for close braces in // specific). So we only smart indent close braces when typed. - return !options.GetOption(BraceCompletionOptions.AutoFormattingOnCloseBrace) || - !options.GetOption(FormattingBehaviorOptions.AutoFormattingOnTyping); + return !options.FormatOnCloseBrace || !options.FormatOnTyping; } - private static bool OnlySmartIndentOpenBrace(DocumentOptionSet options) + private static bool OnlySmartIndentOpenBrace(in AutoFormattingOptions options) { // User does not want auto-formatting . So we only smart indent open braces when typed. // Note: there is no specific option for controlling formatting on open brace. So we // don't have the symmetry with OnlySmartIndentCloseBrace. - return !options.GetOption(FormattingBehaviorOptions.AutoFormattingOnTyping); + return !options.FormatOnTyping; } private static async Task GetTokenBeforeTheCaretAsync(Document document, int caretPosition, CancellationToken cancellationToken) @@ -302,20 +294,20 @@ private static async Task GetTokenBeforeTheCaretAsync(Document docu return token; } - private static async Task> FormatTokenAsync(Document document, OptionSet options, SyntaxToken token, IEnumerable formattingRules, CancellationToken cancellationToken) + private static async Task> FormatTokenAsync(Document document, IndentationOptions options, SyntaxToken token, IEnumerable formattingRules, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var formatter = CreateSmartTokenFormatter(options, formattingRules, root); - var changes = await formatter.FormatTokenAsync(document.Project.Solution.Workspace, token, cancellationToken).ConfigureAwait(false); + var changes = await formatter.FormatTokenAsync(document.Project.Solution.Workspace.Services, token, cancellationToken).ConfigureAwait(false); return changes; } - private static ISmartTokenFormatter CreateSmartTokenFormatter(OptionSet optionSet, IEnumerable formattingRules, SyntaxNode root) - => new CSharpSmartTokenFormatter(optionSet, formattingRules, (CompilationUnitSyntax)root); + private static ISmartTokenFormatter CreateSmartTokenFormatter(IndentationOptions options, IEnumerable formattingRules, SyntaxNode root) + => new CSharpSmartTokenFormatter(options, formattingRules, (CompilationUnitSyntax)root); private static async Task> FormatRangeAsync( Document document, - OptionSet options, + IndentationOptions options, SyntaxToken endToken, IEnumerable formattingRules, CancellationToken cancellationToken) @@ -340,7 +332,7 @@ private static async Task> FormatRangeAsync( var formatter = new CSharpSmartTokenFormatter(options, formattingRules, (CompilationUnitSyntax)root); - var changes = formatter.FormatRange(document.Project.Solution.Workspace, tokenRange.Value.Item1, tokenRange.Value.Item2, cancellationToken); + var changes = formatter.FormatRange(document.Project.Solution.Workspace.Services, tokenRange.Value.Item1, tokenRange.Value.Item2, cancellationToken); return changes.ToImmutableArray(); } diff --git a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs b/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs index 5bb1a6ba4d899..ed8cb0ed896a3 100644 --- a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs @@ -16,6 +16,7 @@ internal class CSharpGenerateDefaultConstructorsCodeFixProvider : AbstractGenera { private const string CS1729 = nameof(CS1729); // 'B' does not contain a constructor that takes 0 arguments CSharpConsoleApp3 C:\Users\cyrusn\source\repos\CSharpConsoleApp3\CSharpConsoleApp3\Program.cs 1 Active private const string CS7036 = nameof(CS7036); // There is no argument given that corresponds to the required formal parameter 's' of 'B.B(string)' + private const string CS8983 = nameof(CS8983); // CS8983: A 'struct' with field initializers must include an explicitly declared constructor. [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -24,6 +25,6 @@ public CSharpGenerateDefaultConstructorsCodeFixProvider() } public override ImmutableArray FixableDiagnosticIds { get; } = - ImmutableArray.Create(CS1729, CS7036); + ImmutableArray.Create(CS1729, CS7036, CS8983); } } diff --git a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs b/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs index e43ccf74d7921..4f44ba38207c4 100644 --- a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs +++ b/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs @@ -40,7 +40,7 @@ protected override bool TryInitializeState( helpers.IsBetweenTypeMembers(semanticDocument.Text, semanticDocument.Root, textSpan.Start, out typeDeclaration)) { classType = semanticDocument.SemanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken) as INamedTypeSymbol; - return classType?.TypeKind == TypeKind.Class; + return classType?.TypeKind is TypeKind.Class or TypeKind.Struct; } var syntaxTree = semanticDocument.SyntaxTree; diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs index ea562fe7ba1a3..6fdd1ec442403 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateVariable/CSharpGenerateVariableService.cs @@ -174,7 +174,7 @@ private static bool IsLegal( return expression.CanReplaceWithLValue(document.SemanticModel, cancellationToken); } - protected override bool TryConvertToLocalDeclaration(ITypeSymbol type, SyntaxToken identifierToken, OptionSet options, SemanticModel semanticModel, CancellationToken cancellationToken, out SyntaxNode newRoot) + protected override bool TryConvertToLocalDeclaration(ITypeSymbol type, SyntaxToken identifierToken, SemanticModel semanticModel, CancellationToken cancellationToken, out SyntaxNode newRoot) { var token = identifierToken; var node = identifierToken.Parent as IdentifierNameSyntax; diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/AsyncAwaitHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/AsyncAwaitHighlighter.cs similarity index 94% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/AsyncAwaitHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/AsyncAwaitHighlighter.cs index b1bc7161ec9c4..0ab3840d6ee87 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/AsyncAwaitHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/AsyncAwaitHighlighter.cs @@ -6,20 +6,19 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class AsyncAwaitHighlighter : AbstractKeywordHighlighter { private static readonly ObjectPool> s_stackPool diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/CheckedExpressionHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/CheckedExpressionHighlighter.cs similarity index 79% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/CheckedExpressionHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/CheckedExpressionHighlighter.cs index b0e5fdf42d7ea..ee149464f227d 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/CheckedExpressionHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/CheckedExpressionHighlighter.cs @@ -6,16 +6,16 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class CheckedExpressionHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/CheckedStatementHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/CheckedStatementHighlighter.cs similarity index 79% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/CheckedStatementHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/CheckedStatementHighlighter.cs index f3536387d11a4..9188fa2b8f8fc 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/CheckedStatementHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/CheckedStatementHighlighter.cs @@ -6,16 +6,16 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class CheckedStatementHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.cs similarity index 85% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.cs index e132ede437184..eea46d21466b9 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.cs @@ -6,17 +6,17 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class ConditionalPreprocessorHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/IfStatementHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/IfStatementHighlighter.cs similarity index 93% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/IfStatementHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/IfStatementHighlighter.cs index c3eb8789c9329..da50a02aeaea2 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/IfStatementHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/IfStatementHighlighter.cs @@ -6,20 +6,20 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class IfStatementHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/LockStatementHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/LockStatementHighlighter.cs similarity index 79% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/LockStatementHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/LockStatementHighlighter.cs index 05bf6c0b93112..deeb539d6f84f 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/LockStatementHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/LockStatementHighlighter.cs @@ -6,16 +6,16 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class LockStatementHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/LoopHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/LoopHighlighter.cs similarity index 94% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/LoopHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/LoopHighlighter.cs index e12ad1f10f106..c4883fd4d444d 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/LoopHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/LoopHighlighter.cs @@ -6,18 +6,18 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class LoopHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/RegionHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/RegionHighlighter.cs similarity index 85% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/RegionHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/RegionHighlighter.cs index e14515f316292..ccd6a104e4422 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/RegionHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/RegionHighlighter.cs @@ -6,17 +6,17 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class RegionHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/ReturnStatementHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/ReturnStatementHighlighter.cs similarity index 90% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/ReturnStatementHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/ReturnStatementHighlighter.cs index 223cada0e0768..53f181f0c3a32 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/ReturnStatementHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/ReturnStatementHighlighter.cs @@ -6,19 +6,19 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class ReturnStatementHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/SwitchStatementHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/SwitchStatementHighlighter.cs similarity index 94% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/SwitchStatementHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/SwitchStatementHighlighter.cs index 856a9d553c608..a6fde5c084c30 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/SwitchStatementHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/SwitchStatementHighlighter.cs @@ -6,19 +6,19 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class SwitchStatementHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/TryStatementHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/TryStatementHighlighter.cs similarity index 85% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/TryStatementHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/TryStatementHighlighter.cs index f920e69be4726..6ec69b0663639 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/TryStatementHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/TryStatementHighlighter.cs @@ -6,16 +6,16 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class TryStatementHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/UnsafeStatementHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/UnsafeStatementHighlighter.cs similarity index 79% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/UnsafeStatementHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/UnsafeStatementHighlighter.cs index d6c817a2b523d..5efdcdb5b4075 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/UnsafeStatementHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/UnsafeStatementHighlighter.cs @@ -6,16 +6,16 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class UnsafeStatementHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/UsingStatementHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/UsingStatementHighlighter.cs similarity index 79% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/UsingStatementHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/UsingStatementHighlighter.cs index c5051842fcbdc..af584d4d2b002 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/UsingStatementHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/UsingStatementHighlighter.cs @@ -6,16 +6,16 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class UsingStatementHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/YieldStatementHighlighter.cs b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/YieldStatementHighlighter.cs similarity index 91% rename from src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/YieldStatementHighlighter.cs rename to src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/YieldStatementHighlighter.cs index dfffb011685b0..44de85bb372fa 100644 --- a/src/EditorFeatures/CSharp/Highlighting/KeywordHighlighters/YieldStatementHighlighter.cs +++ b/src/Features/CSharp/Portable/Highlighting/KeywordHighlighters/YieldStatementHighlighter.cs @@ -6,19 +6,19 @@ using System; using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.Composition; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.Highlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.CSharp.KeywordHighlighting.KeywordHighlighters +namespace Microsoft.CodeAnalysis.CSharp.KeywordHighlighting.KeywordHighlighters { - [ExportHighlighter(LanguageNames.CSharp)] + [ExportHighlighter(LanguageNames.CSharp), Shared] internal class YieldStatementHighlighter : AbstractKeywordHighlighter { [ImportingConstructor] diff --git a/src/Features/CSharp/Portable/ImplementInterface/AbstractChangeImplementionCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/AbstractChangeImplementionCodeRefactoringProvider.cs index 39469714791b0..b26fefffa18c3 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/AbstractChangeImplementionCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/AbstractChangeImplementionCodeRefactoringProvider.cs @@ -41,7 +41,7 @@ internal abstract class AbstractChangeImplementionCodeRefactoringProvider : Code protected abstract bool CheckExplicitNameAllowsConversion(ExplicitInterfaceSpecifierSyntax? explicitName); protected abstract bool CheckMemberCanBeConverted(ISymbol member); - protected abstract SyntaxNode ChangeImplementation(SyntaxGenerator generator, SyntaxNode currentDecl, ISymbol interfaceMember); + protected abstract SyntaxNode ChangeImplementation(SyntaxGenerator generator, SyntaxNode currentDecl, ISymbol implMember, ISymbol interfaceMember); protected abstract Task UpdateReferencesAsync(Project project, SolutionEditor solutionEditor, ISymbol implMember, INamedTypeSymbol containingType, CancellationToken cancellationToken); public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) @@ -220,14 +220,14 @@ await UpdateReferencesAsync( // Now, bucket all the implemented members by which document they appear in. // That way, we can update all the members in a specific document in bulk. - var documentToImplDeclarations = new OrderedMultiDictionary)>(); + var documentToImplDeclarations = new OrderedMultiDictionary interfaceMembers)>(); foreach (var (implMember, interfaceMembers) in implMemberToInterfaceMembers) { foreach (var syntaxRef in implMember.DeclaringSyntaxReferences) { var doc = solution.GetRequiredDocument(syntaxRef.SyntaxTree); var decl = await syntaxRef.GetSyntaxAsync(cancellationToken).ConfigureAwait(false); - documentToImplDeclarations.Add(doc, (decl, interfaceMembers)); + documentToImplDeclarations.Add(doc, (decl, implMember, interfaceMembers)); } } @@ -235,11 +235,12 @@ await UpdateReferencesAsync( { var editor = await solutionEditor.GetDocumentEditorAsync( document.Id, cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - foreach (var (decl, symbols) in declsAndSymbol) + foreach (var (decl, implMember, interfaceMembers) in declsAndSymbol) { editor.ReplaceNode(decl, (currentDecl, g) => - symbols.Select(s => ChangeImplementation(g, currentDecl, s))); + interfaceMembers.Select(s => ChangeImplementation(g, currentDecl, implMember, s))); } } diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementExplicitlyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementExplicitlyCodeRefactoringProvider.cs index 290ec0bd0e99d..ccc0c190a5ffa 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementExplicitlyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementExplicitlyCodeRefactoringProvider.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.Composition; using System.Diagnostics.CodeAnalysis; @@ -53,7 +54,7 @@ protected override async Task UpdateReferencesAsync( // // This can save a lot of extra time spent finding callers, especially for methods with // high fan-out (like IDisposable.Dispose()). - var findRefsOptions = FindReferencesSearchOptions.Default.With(cascade: false); + var findRefsOptions = FindReferencesSearchOptions.Default with { Cascade = false }; var references = await SymbolFinder.FindReferencesAsync( implMember, solution, findRefsOptions, cancellationToken).ConfigureAwait(false); @@ -144,7 +145,39 @@ private static void UpdateLocation( } } - protected override SyntaxNode ChangeImplementation(SyntaxGenerator generator, SyntaxNode decl, ISymbol interfaceMember) - => generator.WithExplicitInterfaceImplementations(decl, ImmutableArray.Create(interfaceMember)); + protected override SyntaxNode ChangeImplementation(SyntaxGenerator generator, SyntaxNode decl, ISymbol implMember, ISymbol interfaceMember) + { + // If these signatures match on default values, then remove the defaults when converting to explicit + // (they're not legal in C#). If they don't match on defaults, then keep them in so that the user gets a + // warning (from us and the compiler) and considers what to do about this. + var removeDefaults = AllDefaultValuesMatch(implMember, interfaceMember); + return generator.WithExplicitInterfaceImplementations(decl, ImmutableArray.Create(interfaceMember), removeDefaults); + } + + private static bool AllDefaultValuesMatch(ISymbol implMember, ISymbol interfaceMember) + { + if (implMember is IMethodSymbol { Parameters: var implParameters } && + interfaceMember is IMethodSymbol { Parameters: var interfaceParameters }) + { + for (int i = 0, n = Math.Max(implParameters.Length, interfaceParameters.Length); i < n; i++) + { + if (!DefaultValueMatches(implParameters[i], interfaceParameters[i])) + return false; + } + } + + return true; + } + + private static bool DefaultValueMatches(IParameterSymbol parameterSymbol1, IParameterSymbol parameterSymbol2) + { + if (parameterSymbol1.HasExplicitDefaultValue != parameterSymbol2.HasExplicitDefaultValue) + return false; + + if (parameterSymbol1.HasExplicitDefaultValue) + return Equals(parameterSymbol1.ExplicitDefaultValue, parameterSymbol2.ExplicitDefaultValue); + + return true; + } } } diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementImplicitlyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementImplicitlyCodeRefactoringProvider.cs index f8e19fee155f0..74eeeec6f9309 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementImplicitlyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementImplicitlyCodeRefactoringProvider.cs @@ -50,10 +50,10 @@ protected override bool CheckMemberCanBeConverted(ISymbol member) protected override Task UpdateReferencesAsync(Project project, SolutionEditor solutionEditor, ISymbol implMember, INamedTypeSymbol containingType, CancellationToken cancellationToken) => Task.CompletedTask; - protected override SyntaxNode ChangeImplementation(SyntaxGenerator generator, SyntaxNode decl, ISymbol _) + protected override SyntaxNode ChangeImplementation(SyntaxGenerator generator, SyntaxNode decl, ISymbol _1, ISymbol _2) => generator.WithAccessibility(WithoutExplicitImpl(decl), Accessibility.Public); - private static SyntaxNode? WithoutExplicitImpl(SyntaxNode decl) + private static SyntaxNode WithoutExplicitImpl(SyntaxNode decl) => decl switch { MethodDeclarationSyntax member => member.WithExplicitInterfaceSpecifier(null), diff --git a/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs index fe936807d8232..fd114d1d3d3ac 100644 --- a/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs @@ -4,17 +4,18 @@ using System; using System.Composition; -using System.Threading.Tasks; using System.Threading; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; 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.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Microsoft.CodeAnalysis.CSharp.InitializeParameter @@ -35,6 +36,13 @@ public CSharpAddParameterCheckCodeRefactoringProvider() { } + protected override ISyntaxFacts SyntaxFacts + => CSharpSyntaxFacts.Instance; + + // We need to be at least on c# 11 to support using !! with records. + protected override bool SupportsRecords(ParseOptions options) + => options.LanguageVersion().IsCSharp11OrAbove(); + protected override bool IsFunctionDeclaration(SyntaxNode node) => InitializeParameterHelpers.IsFunctionDeclaration(node); @@ -97,11 +105,8 @@ protected override StatementSyntax CreateParameterCheckIfStatement(DocumentOptio protected override Document? TryAddNullCheckToParameterDeclaration(Document document, ParameterSyntax parameterSyntax, CancellationToken cancellationToken) { var tree = parameterSyntax.SyntaxTree; - var options = (CSharpParseOptions)tree.Options; - if (options.LanguageVersion < LanguageVersionExtensions.CSharpNext) - { + if (!tree.Options.LanguageVersion().IsCSharp11OrAbove()) return null; - } // We expect the syntax tree to already be in memory since we already have a node from the tree var syntaxRoot = tree.GetRoot(cancellationToken); diff --git a/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs index d163b5a58e249..5113e6cb7d356 100644 --- a/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/InitializeParameter/CSharpInitializeMemberFromParameterCodeRefactoringProvider.cs @@ -5,9 +5,11 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.InitializeParameter; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Operations; namespace Microsoft.CodeAnalysis.CSharp.InitializeParameter @@ -28,6 +30,12 @@ public CSharpInitializeMemberFromParameterCodeRefactoringProvider() { } + protected override ISyntaxFacts SyntaxFacts + => CSharpSyntaxFacts.Instance; + + protected override bool SupportsRecords(ParseOptions options) + => false; + protected override bool IsFunctionDeclaration(SyntaxNode node) => InitializeParameterHelpers.IsFunctionDeclaration(node); diff --git a/src/Features/CSharp/Portable/IntroduceUsingStatement/CSharpIntroduceUsingStatementCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/IntroduceUsingStatement/CSharpIntroduceUsingStatementCodeRefactoringProvider.cs index 01f5dbd4aab35..3a086ec7d0f50 100644 --- a/src/Features/CSharp/Portable/IntroduceUsingStatement/CSharpIntroduceUsingStatementCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/IntroduceUsingStatement/CSharpIntroduceUsingStatementCodeRefactoringProvider.cs @@ -46,16 +46,13 @@ protected override SyntaxNode WithStatements(SyntaxNode parentOfStatementsToSurr throw ExceptionUtilities.UnexpectedValue(parentOfStatementsToSurround); } - protected override StatementSyntax CreateUsingStatement(LocalDeclarationStatementSyntax declarationStatement, SyntaxTriviaList sameLineTrivia, SyntaxList statementsToSurround) - { - var usingStatement = SyntaxFactory.UsingStatement( + protected override StatementSyntax CreateUsingStatement(LocalDeclarationStatementSyntax declarationStatement, SyntaxList statementsToSurround) + => SyntaxFactory.UsingStatement( + SyntaxFactory.Token(SyntaxKind.UsingKeyword).WithLeadingTrivia(declarationStatement.GetLeadingTrivia()), + SyntaxFactory.Token(SyntaxKind.OpenParenToken), declaration: declarationStatement.Declaration.WithoutTrivia(), expression: null, // Declaration already has equals token and expression + SyntaxFactory.Token(SyntaxKind.CloseParenToken).WithTrailingTrivia(declarationStatement.GetTrailingTrivia()), statement: SyntaxFactory.Block(statementsToSurround)); - - return usingStatement - .WithCloseParenToken(usingStatement.CloseParenToken - .WithTrailingTrivia(sameLineTrivia)); - } } } diff --git a/src/Features/CSharp/Portable/LanguageServices/CSharpStructuralTypeDisplayService.cs b/src/Features/CSharp/Portable/LanguageServices/CSharpStructuralTypeDisplayService.cs index 0a414ce2768af..756829e0902e3 100644 --- a/src/Features/CSharp/Portable/LanguageServices/CSharpStructuralTypeDisplayService.cs +++ b/src/Features/CSharp/Portable/LanguageServices/CSharpStructuralTypeDisplayService.cs @@ -10,6 +10,7 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PooledObjects; @@ -26,7 +27,9 @@ public CSharpStructuralTypeDisplayService() { } - public override ImmutableArray GetAnonymousTypeParts( + protected override ISyntaxFacts SyntaxFactsService => CSharpSyntaxFacts.Instance; + + protected override ImmutableArray GetNormalAnonymousTypeParts( INamedTypeSymbol anonymousType, SemanticModel semanticModel, int position) { using var _ = ArrayBuilder.GetInstance(out var members); diff --git a/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.SymbolDescriptionBuilder.cs b/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.SymbolDescriptionBuilder.cs index 62fe451699e51..31f2839c0402d 100644 --- a/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.SymbolDescriptionBuilder.cs +++ b/src/Features/CSharp/Portable/LanguageServices/CSharpSymbolDisplayService.SymbolDescriptionBuilder.cs @@ -214,12 +214,6 @@ protected override void AddCaptures(ISymbol symbol) } } - protected override void InlineAllDelegateAnonymousTypes(SemanticModel semanticModel, int position, IStructuralTypeDisplayService structuralTypeDisplayService, Dictionary> groupMap) - { - // In C#, anonymous delegates are typically represented with System.Action<> or System.Func<>, - // and we prefer to display those types rather than a structural delegate type. - } - protected override SymbolDisplayFormat MinimallyQualifiedFormat => s_minimallyQualifiedFormat; protected override SymbolDisplayFormat MinimallyQualifiedFormatWithConstants => s_minimallyQualifiedFormatWithConstants; diff --git a/src/EditorFeatures/CSharp/LineSeparators/CSharpLineSeparatorService.cs b/src/Features/CSharp/Portable/LineSeparators/CSharpLineSeparatorService.cs similarity index 94% rename from src/EditorFeatures/CSharp/LineSeparators/CSharpLineSeparatorService.cs rename to src/Features/CSharp/Portable/LineSeparators/CSharpLineSeparatorService.cs index 41c5b4d2b7755..80c2d9071ec8f 100644 --- a/src/EditorFeatures/CSharp/LineSeparators/CSharpLineSeparatorService.cs +++ b/src/Features/CSharp/Portable/LineSeparators/CSharpLineSeparatorService.cs @@ -4,18 +4,20 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LineSeparators; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.CSharp.LineSeparator +namespace Microsoft.CodeAnalysis.CSharp.LineSeparators { [ExportLanguageService(typeof(ILineSeparatorService), LanguageNames.CSharp), Shared] internal class CSharpLineSeparatorService : ILineSeparatorService @@ -30,21 +32,21 @@ public CSharpLineSeparatorService() /// Given a tree returns line separator spans. /// The operation may take fairly long time on a big tree so it is cancellable. /// - public async Task> GetLineSeparatorsAsync( + public async Task> GetLineSeparatorsAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken) { var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var node = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false); - var spans = new List(); + using var _ = ArrayBuilder.GetInstance(out var spans); var blocks = node.Traverse(textSpan, IsSeparableContainer); foreach (var block in blocks) { if (cancellationToken.IsCancellationRequested) - return SpecializedCollections.EmptyEnumerable(); + return ImmutableArray.Empty; switch (block) { @@ -62,7 +64,7 @@ public async Task> GetLineSeparatorsAsync( } } - return spans; + return spans.ToImmutable(); } /// Node types that are interesting for line separation. @@ -240,7 +242,7 @@ private static bool IsBadNode(SyntaxNode node) return false; } - private static void ProcessUsings(SyntaxList usings, List spans, CancellationToken cancellationToken) + private static void ProcessUsings(SyntaxList usings, ArrayBuilder spans, CancellationToken cancellationToken) { Contract.ThrowIfNull(spans); @@ -255,7 +257,7 @@ private static void ProcessUsings(SyntaxList usings, List< /// If node is separable and not the first in its container => ensure separator before the node /// last separable node in Program needs separator after it. /// - private static void ProcessNodeList(SyntaxList children, List spans, CancellationToken cancellationToken) where T : SyntaxNode + private static void ProcessNodeList(SyntaxList children, ArrayBuilder spans, CancellationToken cancellationToken) where T : SyntaxNode { Contract.ThrowIfNull(spans); @@ -308,7 +310,7 @@ private static void ProcessNodeList(SyntaxList children, List sp } } - private static void AddLineSeparatorSpanForNode(SyntaxNode node, List spans, CancellationToken cancellationToken) + private static void AddLineSeparatorSpanForNode(SyntaxNode node, ArrayBuilder spans, CancellationToken cancellationToken) { if (IsBadNode(node)) { diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs index ab930386c5651..4c637bbff1f57 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs @@ -28,7 +28,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); + var syntaxEditor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); await MakeLocalFunctionStaticAsync(document, localFunction, captures, syntaxEditor, cancellationToken).ConfigureAwait(false); return document.WithSyntaxRoot(syntaxEditor.GetChangedRoot()); } @@ -138,15 +138,19 @@ public static async Task MakeLocalFunctionStaticAsync( } } + var codeGenerator = document.GetRequiredLanguageService(); + var options = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, document, cancellationToken).ConfigureAwait(false); + // Updates the local function declaration with variables passed in as parameters syntaxEditor.ReplaceNode( localFunction, (node, generator) => { - var localFunctionWithNewParameters = CodeGenerator.AddParameterDeclarations( + var localFunctionWithNewParameters = codeGenerator.AddParameters( node, parameterAndCapturedSymbols.SelectAsArray(p => p.symbol), - document.Project.Solution.Workspace); + options, + cancellationToken); if (shouldWarn) { diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs index 3a80dc9a83628..40b5e172323c3 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.CodeAnalysis.CSharp.MakeLocalFunctionStatic @@ -27,7 +28,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var (document, textSpan, cancellationToken) = context; var syntaxTree = (await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false))!; - if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(((CSharpParseOptions)syntaxTree.Options).LanguageVersion)) + if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(syntaxTree.Options.LanguageVersion())) { return; } diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs index d2d9b23211f3c..e82692de0fcc7 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Roslyn.Utilities; @@ -78,10 +79,8 @@ private static async Task WrapFixAsync( // Even when the language version doesn't support staic local function, the compiler will still // generate this error. So we need to check to make sure we don't provide incorrect fix. - if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(((CSharpParseOptions)root.SyntaxTree.Options).LanguageVersion)) - { + if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(root.SyntaxTree.Options.LanguageVersion())) return; - } // Find all unique local functions that contain the error. var localFunctions = diagnostics diff --git a/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs b/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs index fa4a1ecc15d44..ecf15b6b8d3ed 100644 --- a/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs +++ b/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs @@ -45,8 +45,9 @@ public void ReplaceGetMethodWithProperty( return; } + var languageVersion = parseOptions.LanguageVersion(); var newProperty = ConvertMethodsToProperty( - documentOptions, parseOptions, + documentOptions, languageVersion, semanticModel, editor.Generator, getAndSetMethods, propertyName, nameChanged); @@ -54,12 +55,12 @@ public void ReplaceGetMethodWithProperty( } public static SyntaxNode ConvertMethodsToProperty( - DocumentOptionSet documentOptions, ParseOptions parseOptions, + DocumentOptionSet documentOptions, LanguageVersion languageVersion, SemanticModel semanticModel, SyntaxGenerator generator, GetAndSetMethods getAndSetMethods, string propertyName, bool nameChanged) { var propertyDeclaration = ConvertMethodsToPropertyWorker( - documentOptions, parseOptions, semanticModel, + documentOptions, languageVersion, semanticModel, generator, getAndSetMethods, propertyName, nameChanged); var expressionBodyPreference = documentOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties).Value; @@ -77,7 +78,7 @@ public static SyntaxNode ConvertMethodsToProperty( } else if (getAccessor.Body != null && getAccessor.Body.TryConvertToArrowExpressionBody( - propertyDeclaration.Kind(), parseOptions, expressionBodyPreference, + propertyDeclaration.Kind(), languageVersion, expressionBodyPreference, out var arrowExpression, out var semicolonToken)) { return propertyDeclaration.WithExpressionBody(arrowExpression) @@ -109,14 +110,14 @@ public static SyntaxNode ConvertMethodsToProperty( } public static PropertyDeclarationSyntax ConvertMethodsToPropertyWorker( - DocumentOptionSet documentOptions, ParseOptions parseOptions, + DocumentOptionSet documentOptions, LanguageVersion languageVersion, SemanticModel semanticModel, SyntaxGenerator generator, GetAndSetMethods getAndSetMethods, string propertyName, bool nameChanged) { var getMethodDeclaration = (MethodDeclarationSyntax)getAndSetMethods.GetMethodDeclaration; var setMethodDeclaration = getAndSetMethods.SetMethodDeclaration as MethodDeclarationSyntax; - var getAccessor = CreateGetAccessor(getAndSetMethods, documentOptions, parseOptions); - var setAccessor = CreateSetAccessor(semanticModel, generator, getAndSetMethods, documentOptions, parseOptions); + var getAccessor = CreateGetAccessor(getAndSetMethods, documentOptions, languageVersion); + var setAccessor = CreateSetAccessor(semanticModel, generator, getAndSetMethods, documentOptions, languageVersion); var nameToken = GetPropertyName(getMethodDeclaration.Identifier, propertyName, nameChanged); var warning = GetWarning(getAndSetMethods); @@ -159,23 +160,23 @@ private static SyntaxToken GetPropertyName(SyntaxToken identifier, string proper } private static AccessorDeclarationSyntax CreateGetAccessor( - GetAndSetMethods getAndSetMethods, DocumentOptionSet documentOptions, ParseOptions parseOptions) + GetAndSetMethods getAndSetMethods, DocumentOptionSet documentOptions, LanguageVersion languageVersion) { var accessorDeclaration = CreateGetAccessorWorker(getAndSetMethods); return UseExpressionOrBlockBodyIfDesired( - documentOptions, parseOptions, accessorDeclaration); + documentOptions, languageVersion, accessorDeclaration); } private static AccessorDeclarationSyntax UseExpressionOrBlockBodyIfDesired( - DocumentOptionSet documentOptions, ParseOptions parseOptions, + DocumentOptionSet documentOptions, LanguageVersion languageVersion, AccessorDeclarationSyntax accessorDeclaration) { var expressionBodyPreference = documentOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors).Value; if (accessorDeclaration?.Body != null && expressionBodyPreference != ExpressionBodyPreference.Never) { if (accessorDeclaration.Body.TryConvertToArrowExpressionBody( - accessorDeclaration.Kind(), parseOptions, expressionBodyPreference, + accessorDeclaration.Kind(), languageVersion, expressionBodyPreference, out var arrowExpression, out var semicolonToken)) { return accessorDeclaration.WithBody(null) @@ -228,10 +229,10 @@ private static AccessorDeclarationSyntax CreateGetAccessorWorker(GetAndSetMethod private static AccessorDeclarationSyntax CreateSetAccessor( SemanticModel semanticModel, SyntaxGenerator generator, GetAndSetMethods getAndSetMethods, - DocumentOptionSet documentOptions, ParseOptions parseOptions) + DocumentOptionSet documentOptions, LanguageVersion languageVersion) { var accessorDeclaration = CreateSetAccessorWorker(semanticModel, generator, getAndSetMethods); - return UseExpressionOrBlockBodyIfDesired(documentOptions, parseOptions, accessorDeclaration); + return UseExpressionOrBlockBodyIfDesired(documentOptions, languageVersion, accessorDeclaration); } private static AccessorDeclarationSyntax CreateSetAccessorWorker( diff --git a/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs b/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs index 2eeda8968d211..9d9c92bf78400 100644 --- a/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs +++ b/src/Features/CSharp/Portable/ReplacePropertyWithMethods/CSharpReplacePropertyWithMethodsService.cs @@ -47,10 +47,10 @@ public override async Task> GetReplacementMembersAsyn var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var parseOptions = syntaxTree.Options; + var languageVersion = syntaxTree.Options.LanguageVersion(); return ConvertPropertyToMembers( - documentOptions, parseOptions, + documentOptions, languageVersion, SyntaxGenerator.GetGenerator(document), property, propertyDeclaration, propertyBackingField, desiredGetMethodName, desiredSetMethodName, @@ -59,7 +59,7 @@ public override async Task> GetReplacementMembersAsyn private static ImmutableArray ConvertPropertyToMembers( DocumentOptionSet documentOptions, - ParseOptions parseOptions, + LanguageVersion languageVersion, SyntaxGenerator generator, IPropertySymbol property, PropertyDeclarationSyntax propertyDeclaration, @@ -80,7 +80,7 @@ private static ImmutableArray ConvertPropertyToMembers( if (getMethod != null) { result.Add(GetGetMethod( - documentOptions, parseOptions, + documentOptions, languageVersion, generator, propertyDeclaration, propertyBackingField, getMethod, desiredGetMethodName, cancellationToken: cancellationToken)); @@ -90,7 +90,7 @@ private static ImmutableArray ConvertPropertyToMembers( if (setMethod != null) { result.Add(GetSetMethod( - documentOptions, parseOptions, + documentOptions, languageVersion, generator, propertyDeclaration, propertyBackingField, setMethod, desiredSetMethodName, cancellationToken: cancellationToken)); @@ -101,7 +101,7 @@ private static ImmutableArray ConvertPropertyToMembers( private static SyntaxNode GetSetMethod( DocumentOptionSet documentOptions, - ParseOptions parseOptions, + LanguageVersion languageVersion, SyntaxGenerator generator, PropertyDeclarationSyntax propertyDeclaration, IFieldSymbol? propertyBackingField, @@ -118,7 +118,7 @@ private static SyntaxNode GetSetMethod( methodDeclaration = CopyLeadingTrivia(propertyDeclaration, methodDeclaration, ConvertValueToParamRewriter.Instance); return UseExpressionOrBlockBodyIfDesired( - documentOptions, parseOptions, methodDeclaration, + documentOptions, languageVersion, methodDeclaration, createReturnStatementForExpression: false); } @@ -165,7 +165,7 @@ private static MethodDeclarationSyntax GetSetMethodWorker( private static SyntaxNode GetGetMethod( DocumentOptionSet documentOptions, - ParseOptions parseOptions, + LanguageVersion languageVersion, SyntaxGenerator generator, PropertyDeclarationSyntax propertyDeclaration, IFieldSymbol? propertyBackingField, @@ -180,7 +180,7 @@ private static SyntaxNode GetGetMethod( methodDeclaration = CopyLeadingTrivia(propertyDeclaration, methodDeclaration, ConvertValueToReturnsRewriter.Instance); return UseExpressionOrBlockBodyIfDesired( - documentOptions, parseOptions, methodDeclaration, + documentOptions, languageVersion, methodDeclaration, createReturnStatementForExpression: true); } @@ -213,14 +213,14 @@ private static SyntaxTrivia ConvertDocumentationComment(SyntaxTrivia trivia, CSh } private static SyntaxNode UseExpressionOrBlockBodyIfDesired( - DocumentOptionSet documentOptions, ParseOptions parseOptions, + DocumentOptionSet documentOptions, LanguageVersion languageVersion, MethodDeclarationSyntax methodDeclaration, bool createReturnStatementForExpression) { var expressionBodyPreference = documentOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods).Value; if (methodDeclaration.Body != null && expressionBodyPreference != ExpressionBodyPreference.Never) { if (methodDeclaration.Body.TryConvertToArrowExpressionBody( - methodDeclaration.Kind(), parseOptions, expressionBodyPreference, + methodDeclaration.Kind(), languageVersion, expressionBodyPreference, out var arrowExpression, out var semicolonToken)) { return methodDeclaration.WithBody(null) diff --git a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs index 1e487cd90b844..9a8c32a78477c 100644 --- a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs @@ -264,7 +264,7 @@ private async Task ReverseForStatementAsync( var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); + var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.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 new file mode 100644 index 0000000000000..b84f71bcc31f9 --- /dev/null +++ b/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.LightweightOverloadResolution.cs @@ -0,0 +1,296 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp +{ + internal abstract partial class AbstractCSharpSignatureHelpProvider + { + internal static class LightweightOverloadResolution + { + public static void RefineOverloadAndPickParameter(Document document, int position, SemanticModel semanticModel, + ImmutableArray candidates, SeparatedSyntaxList arguments, + out IMethodSymbol? currentSymbol, out int parameterIndex) + { + var semanticFactsService = document.GetRequiredLanguageService(); + if (candidates.Length == 1) + { + // The compiler told us the correct overload or we only have one choice, but we need to find out the parameter to highlight given cursor position + currentSymbol = candidates[0]; + _ = FindParameterIndexIfCompatibleMethod(arguments, currentSymbol, position, semanticModel, semanticFactsService, out parameterIndex); + } + else + { + (currentSymbol, parameterIndex) = GuessCurrentSymbolAndParameter(arguments, candidates, position, semanticModel, semanticFactsService); + } + } + + /// + /// If the symbol could not be bound, we could be dealing with a partial invocation, we'll try to find a possible overload. + /// + private static (IMethodSymbol? symbol, int parameterIndex) GuessCurrentSymbolAndParameter( + SeparatedSyntaxList arguments, ImmutableArray methodGroup, int position, + SemanticModel semanticModel, ISemanticFactsService semanticFactsService) + { + if (arguments.Count != 0) + { + foreach (var method in methodGroup) + { + if (FindParameterIndexIfCompatibleMethod(arguments, method, position, semanticModel, semanticFactsService, out var parameterIndex)) + { + return (method, parameterIndex); + } + } + } + + // Note: Providing no recommendation if no arguments allows the model to keep the last implicit choice + return (null, -1); + } + + /// + /// Simulates overload resolution with the arguments provided so far and determines if you might be calling this overload. + /// Returns true if an overload is acceptable. In that case, we output the parameter that should be highlighted given the cursor's + /// position in the partial invocation. + /// + internal static bool FindParameterIndexIfCompatibleMethod(SeparatedSyntaxList arguments, IMethodSymbol method, int position, + SemanticModel semanticModel, ISemanticFactsService semanticFactsService, out int foundParameterIndex) + { + // map the arguments to their corresponding parameters + var argumentCount = arguments.Count; + using var _ = ArrayBuilder.GetInstance(argumentCount, fillWithValue: -1, out var argToParamMap); + if (!TryPrepareArgToParamMap(arguments, method, argToParamMap)) + { + foundParameterIndex = -1; + return false; + } + + // verify that the arguments are compatible with their corresponding parameters + var parameters = method.Parameters; + for (var argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) + { + var parameterIndex = argToParamMap[argumentIndex]; + if (parameterIndex < 0) + { + continue; + } + + var parameter = parameters[parameterIndex]; + var argument = arguments[argumentIndex]; + + if (!IsCompatibleArgument(argument, parameter)) + { + foundParameterIndex = -1; + return false; + } + } + + // find the parameter at the cursor position + var argumentIndexToSave = TryGetArgumentIndex(arguments, position); + if (argumentIndexToSave >= 0) + { + var foundParam = argToParamMap[argumentIndexToSave]; + if (foundParam >= 0) + { + foundParameterIndex = foundParam; + } + else + { + foundParameterIndex = FirstUnspecifiedParameter(argToParamMap, argumentCount); + } + } + else + { + foundParameterIndex = -1; + } + + Debug.Assert(foundParameterIndex < parameters.Length); + + return true; + + // If the cursor is pointing at an argument for which we did not find the corresponding + // parameter, we will highlight the first unspecified parameter. + static int FirstUnspecifiedParameter(ArrayBuilder argToParamMap, int argumentCount) + { + using var _ = ArrayBuilder.GetInstance(argumentCount, false, out var specified); + for (var i = 0; i < argumentCount; i++) + { + var parameterIndex = argToParamMap[i]; + if (parameterIndex >= 0) + { + specified[parameterIndex] = true; + } + } + + var first = specified.FindIndex(s => !s); + return first <= 0 ? 0 : first; + } + + // Determines if the given argument is compatible with the given parameter + bool IsCompatibleArgument(ArgumentSyntax argument, IParameterSymbol parameter) + { + var parameterRefKind = parameter.RefKind; + if (parameterRefKind == RefKind.None) + { + if (IsEmptyArgument(argument.Expression)) + { + // An argument left empty is considered to match any parameter + // M(1, $$) + // M(1, , 2$$) + return true; + } + + var type = parameter.Type; + if (parameter.IsParams + && type is IArrayTypeSymbol arrayType + && HasImplicitConversion(argument.Expression, arrayType.ElementType)) + { + return true; + } + + return HasImplicitConversion(argument.Expression, type); + } + + var argumentRefKind = argument.GetRefKind(); + if (parameterRefKind == RefKind.In && argumentRefKind == RefKind.None) + { + // A by-value argument matches an `in` parameter + return true; + } + + if (parameterRefKind == argumentRefKind) + { + return true; + } + + return false; + } + + bool HasImplicitConversion(SyntaxNode expression, ITypeSymbol destination) + { + var conversion = semanticFactsService.ClassifyConversion(semanticModel, expression, destination); + return conversion.IsImplicit; + } + } + + /// + /// Find the parameter index corresponding to each argument provided + /// + private static bool TryPrepareArgToParamMap(SeparatedSyntaxList arguments, IMethodSymbol method, ArrayBuilder argToParamMap) + { + var parameters = method.Parameters; + var parameterCount = parameters.Length; + var currentParameterIndex = 0; + var seenOutOfPositionArgument = false; + var inParams = false; + + for (var argumentIndex = 0; argumentIndex < arguments.Count; argumentIndex++) + { + if (argumentIndex >= parameterCount && !inParams) + { + return false; + } + + var argument = arguments[argumentIndex]; + if (HasName(argument, out var name)) + { + var namedParameterIndex = parameters.IndexOf(p => p.Name == name); + if (namedParameterIndex < 0) + { + return false; + } + + if (namedParameterIndex != currentParameterIndex) + { + seenOutOfPositionArgument = true; + } + + AddArgToParamMapping(argumentIndex, namedParameterIndex); + IncrementParameterIndexIfNeeded(); + } + else if (IsEmptyArgument(argument.Expression)) + { + if (!seenOutOfPositionArgument) + { + // We count the empty argument as a used position + AddArgToParamMapping(argumentIndex, currentParameterIndex); + IncrementParameterIndexIfNeeded(); + } + } + else if (seenOutOfPositionArgument) + { + // Unnamed arguments are not allowed after an out-of-position argument + return false; + } + else + { + AddArgToParamMapping(argumentIndex, currentParameterIndex); + IncrementParameterIndexIfNeeded(); + } + } + + return true; + + void IncrementParameterIndexIfNeeded() + { + if (!seenOutOfPositionArgument && !inParams) + { + currentParameterIndex++; + } + } + + void AddArgToParamMapping(int argumentIndex, int parameterIndex) + { + Debug.Assert(parameterIndex >= 0); + Debug.Assert(parameterIndex < parameterCount); + + inParams |= parameters[parameterIndex].IsParams; + argToParamMap[argumentIndex] = parameterIndex; + } + } + + private static bool IsEmptyArgument(ExpressionSyntax expression) + => expression.Span.IsEmpty; + + /// + /// Given the cursor position, find which argument is active. + /// This will be useful to later find which parameter should be highlighted. + /// + private static int TryGetArgumentIndex(SeparatedSyntaxList arguments, int position) + { + if (arguments.Count == 0) + { + return -1; + } + + for (var i = 0; i < arguments.Count - 1; i++) + { + // `$$,` points to the argument before the separator + // but `,$$` points to the argument following the separator + if (position <= arguments.GetSeparator(i).Span.Start) + { + return i; + } + } + + return arguments.Count - 1; + } + + private static bool HasName(ArgumentSyntax argument, [NotNullWhen(true)] out string? name) + { + name = argument.NameColon?.Name.Identifier.ValueText; + return name != null; + } + } + } +} diff --git a/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs index c91c5e0f2c026..bc9112ce2f57a 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs @@ -4,14 +4,24 @@ 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.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp { - internal abstract class AbstractCSharpSignatureHelpProvider : AbstractSignatureHelpProvider + internal abstract partial class AbstractCSharpSignatureHelpProvider : AbstractSignatureHelpProvider { private static readonly SymbolDisplayFormat s_allowDefaultLiteralFormat = SymbolDisplayFormat.MinimallyQualifiedFormat .AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.AllowDefaultLiteral); diff --git a/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs index cc6168698fbff..11ef37b89d8c4 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs @@ -105,7 +105,7 @@ private static bool IsArgumentListToken(AttributeSyntax expression, SyntaxToken textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken), selectedItem); } - public override SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) + private SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) { if (TryGetAttributeExpression(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, out var expression) && currentSpan.Start == SignatureHelpUtilities.GetSignatureHelpSpan(expression.ArgumentList!).Start) diff --git a/src/Features/CSharp/Portable/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs index c2ae01b6700bd..351c434432433 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Composition; using System.Linq; using System.Threading; @@ -86,37 +87,44 @@ private static bool IsArgumentListToken(ConstructorInitializerSyntax expression, return null; } + // get the candidate methods var currentConstructor = semanticModel.GetDeclaredSymbol(constructorInitializer.Parent!, cancellationToken); - var accessibleConstructors = type.InstanceConstructors - .WhereAsArray(c => c.IsAccessibleWithin(within) && !c.Equals(currentConstructor)) - .WhereAsArray(c => c.IsEditorBrowsable(options.HideAdvancedMembers, semanticModel.Compilation)) - .Sort(semanticModel, constructorInitializer.SpanStart); + var constructors = type.InstanceConstructors + .WhereAsArray(c => c.IsAccessibleWithin(within) && !c.Equals(currentConstructor)) + .WhereAsArray(c => c.IsEditorBrowsable(options.HideAdvancedMembers, semanticModel.Compilation)) + .Sort(semanticModel, constructorInitializer.SpanStart); - if (!accessibleConstructors.Any()) + if (!constructors.Any()) { return null; } + // guess the best candidate if needed and determine parameter index + var arguments = constructorInitializer.ArgumentList.Arguments; + var candidates = semanticModel.GetSymbolInfo(constructorInitializer, cancellationToken).Symbol is IMethodSymbol exactSymbol + ? ImmutableArray.Create(exactSymbol) + : constructors; + LightweightOverloadResolution.RefineOverloadAndPickParameter(document, position, semanticModel, candidates, arguments, out var currentSymbol, out var parameterIndex); + + // present items and select + var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(constructorInitializer.ArgumentList); var structuralTypeDisplayService = document.GetRequiredLanguageService(); var documentationCommentFormattingService = document.GetRequiredLanguageService(); - var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(constructorInitializer.ArgumentList); - var syntaxFacts = document.GetRequiredLanguageService(); - var symbolInfo = semanticModel.GetSymbolInfo(constructorInitializer, cancellationToken); - var selectedItem = TryGetSelectedIndex(accessibleConstructors, symbolInfo.Symbol); + var items = constructors.SelectAsArray(m => Convert(m, constructorInitializer.ArgumentList.OpenParenToken, semanticModel, structuralTypeDisplayService, documentationCommentFormattingService)); + var selectedItem = TryGetSelectedIndex(constructors, currentSymbol); - return CreateSignatureHelpItems(accessibleConstructors.SelectAsArray(c => - Convert(c, constructorInitializer.ArgumentList.OpenParenToken, semanticModel, structuralTypeDisplayService, documentationCommentFormattingService)).ToList(), - textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken), selectedItem); + var syntaxFacts = document.GetRequiredLanguageService(); + return CreateSignatureHelpItems(items, textSpan, GetCurrentArgumentState(root, position, parameterIndex, syntaxFacts, textSpan, cancellationToken), selectedItem); } - public override SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) + private SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, int parameterIndex, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) { if (TryGetConstructorInitializer(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, out var expression) && currentSpan.Start == SignatureHelpUtilities.GetSignatureHelpSpan(expression.ArgumentList).Start) { - return SignatureHelpUtilities.GetSignatureHelpState(expression.ArgumentList, position); + return SignatureHelpUtilities.GetSignatureHelpState(expression.ArgumentList, position, parameterIndex); } return null; diff --git a/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs index 3374d16103ebe..2e2cf111ffece 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs @@ -132,7 +132,7 @@ private static TextSpan GetTextSpan(ExpressionSyntax expression, SyntaxToken ope throw ExceptionUtilities.Unreachable; } - public override SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) + private static SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) { if (!TryGetElementAccessExpression( root, diff --git a/src/Features/CSharp/Portable/SignatureHelp/GenericNameSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/GenericNameSignatureHelpProvider.cs index 4fd9d84df0e2e..c5c0b0f8a25a2 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/GenericNameSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/GenericNameSignatureHelpProvider.cs @@ -133,10 +133,10 @@ private bool IsArgumentListToken(GenericNameSyntax node, SyntaxToken token) return CreateSignatureHelpItems(accessibleSymbols.Select(s => Convert(s, lessThanToken, semanticModel, structuralTypeDisplayService, documentationCommentFormattingService)).ToList(), - textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken), selectedItem: null); + textSpan, GetCurrentArgumentState(root, position, syntaxFacts, cancellationToken), selectedItem: null); } - public override SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) + private SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken) { if (!TryGetGenericIdentifier(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, out var genericIdentifier, out _)) diff --git a/src/Features/CSharp/Portable/SignatureHelp/InitializerExpressionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/InitializerExpressionSignatureHelpProvider.cs index 5ef587ee38ba0..c4ed12f2fd9f9 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/InitializerExpressionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/InitializerExpressionSignatureHelpProvider.cs @@ -68,7 +68,7 @@ private static bool IsInitializerExpressionToken(InitializerExpressionSyntax exp textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)); } - public override SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) + private SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) { if (TryGetInitializerExpression( root, diff --git a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.cs index f1f691b646f37..1a52894137f65 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.cs @@ -3,8 +3,10 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -17,6 +19,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp { @@ -72,62 +75,94 @@ private static bool IsArgumentListToken(InvocationExpressionSyntax expression, S return null; } - // get the regular signature help items - var methodGroup = semanticModel.GetMemberGroup(invocationExpression.Expression, cancellationToken) - .OfType() - .ToImmutableArray() - .FilterToVisibleAndBrowsableSymbols(options.HideAdvancedMembers, semanticModel.Compilation); + var invokedType = semanticModel.GetTypeInfo(invocationExpression.Expression, cancellationToken).Type; + if (invokedType is INamedTypeSymbol { TypeKind: TypeKind.Delegate } + || invokedType is IFunctionPointerTypeSymbol) + { + return await GetItemsWorkerForDelegateOrFunctionPointerAsync(document, position, invocationExpression, within, cancellationToken).ConfigureAwait(false); + } + + // get the candidate methods + var symbolDisplayService = document.GetLanguageService(); + var methods = semanticModel.GetMemberGroup(invocationExpression.Expression, cancellationToken) + .OfType() + .ToImmutableArray() + .FilterToVisibleAndBrowsableSymbols(options.HideAdvancedMembers, semanticModel.Compilation); + methods = GetAccessibleMethods(invocationExpression, semanticModel, within, methods, cancellationToken); + methods = methods.Sort(semanticModel, invocationExpression.SpanStart); + + if (!methods.Any()) + { + return null; + } - // try to bind to the actual method + // guess the best candidate if needed and determine parameter index + var arguments = invocationExpression.ArgumentList.Arguments; var symbolInfo = semanticModel.GetSymbolInfo(invocationExpression, cancellationToken); + var candidates = symbolInfo.Symbol is IMethodSymbol exactMatch + ? ImmutableArray.Create(exactMatch) + : methods; + LightweightOverloadResolution.RefineOverloadAndPickParameter(document, position, semanticModel, candidates, arguments, out var currentSymbol, out var parameterIndex); // if the symbol could be bound, replace that item in the symbol list - if (symbolInfo.Symbol is IMethodSymbol matchedMethodSymbol && matchedMethodSymbol.IsGenericMethod) + if (currentSymbol?.IsGenericMethod == true) { - methodGroup = methodGroup.SelectAsArray(m => Equals(matchedMethodSymbol.OriginalDefinition, m) ? matchedMethodSymbol : m); + methods = methods.SelectAsArray(m => Equals(currentSymbol.OriginalDefinition, m) ? currentSymbol : m); } - methodGroup = methodGroup.Sort( - semanticModel, invocationExpression.SpanStart); - - var structuralTypeDisplayService = document.Project.LanguageServices.GetRequiredService(); - var documentationCommentFormattingService = document.Project.LanguageServices.GetRequiredService(); + // present items and select + var (items, selectedItem) = await GetMethodGroupItemsAndSelectionAsync( + methods, document, invocationExpression, semanticModel, symbolInfo, currentSymbol, cancellationToken).ConfigureAwait(false); var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(invocationExpression.ArgumentList); var syntaxFacts = document.GetRequiredLanguageService(); + return CreateSignatureHelpItems(items, textSpan, GetCurrentArgumentState(root, position, parameterIndex, syntaxFacts, textSpan, cancellationToken), selectedItem); + } - if (methodGroup.Any()) - { - var accessibleMethods = GetAccessibleMethods(invocationExpression, semanticModel, within, methodGroup, cancellationToken); - var (items, selectedItem) = await GetMethodGroupItemsAndSelectionAsync(accessibleMethods, document, invocationExpression, semanticModel, symbolInfo, cancellationToken).ConfigureAwait(false); - - return CreateSignatureHelpItems( - items, - textSpan, - GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken), - selectedItem); - } + protected async Task GetItemsWorkerForDelegateOrFunctionPointerAsync(Document document, int position, + InvocationExpressionSyntax invocationExpression, ISymbol within, CancellationToken cancellationToken) + { + var semanticModel = await document.ReuseExistingSpeculativeModelAsync(invocationExpression, cancellationToken).ConfigureAwait(false); var invokedType = semanticModel.GetTypeInfo(invocationExpression.Expression, cancellationToken).Type; - if (invokedType is INamedTypeSymbol expressionType && expressionType.TypeKind == TypeKind.Delegate) + IMethodSymbol? currentSymbol; + if (invokedType is INamedTypeSymbol { TypeKind: TypeKind.Delegate } expressionType) { - var items = GetDelegateInvokeItems(invocationExpression, semanticModel, structuralTypeDisplayService, - documentationCommentFormattingService, within, expressionType, out var selectedItem, cancellationToken); - - return CreateSignatureHelpItems(items, textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken), selectedItem); + currentSymbol = GetDelegateInvokeMethod(invocationExpression, semanticModel, within, expressionType, cancellationToken); } else if (invokedType is IFunctionPointerTypeSymbol functionPointerType) { - var items = GetFunctionPointerInvokeItems(invocationExpression, semanticModel, structuralTypeDisplayService, - documentationCommentFormattingService, functionPointerType, out var selectedItem, cancellationToken); + currentSymbol = functionPointerType.Signature; + } + else + { + throw ExceptionUtilities.Unreachable; + } - return CreateSignatureHelpItems(items, textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken), selectedItem); + if (currentSymbol is null) + { + return null; } - return null; + // determine parameter index + var arguments = invocationExpression.ArgumentList.Arguments; + var semanticFactsService = document.GetRequiredLanguageService(); + LightweightOverloadResolution.FindParameterIndexIfCompatibleMethod(arguments, currentSymbol, position, semanticModel, semanticFactsService, out var parameterIndex); + + // present item and select + var structuralTypeDisplayService = document.Project.LanguageServices.GetRequiredService(); + var documentationCommentFormattingService = document.GetRequiredLanguageService(); + + var items = GetDelegateOrFunctionPointerInvokeItems(invocationExpression, currentSymbol, + semanticModel, structuralTypeDisplayService, documentationCommentFormattingService, out var selectedItem, cancellationToken); + + var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(invocationExpression.ArgumentList); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var syntaxFacts = document.GetRequiredLanguageService(); + return CreateSignatureHelpItems(items, textSpan, GetCurrentArgumentState(root, position, parameterIndex, syntaxFacts, textSpan, cancellationToken), selectedItem); } - public override SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) + private SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, int parameterIndex, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) { if (TryGetInvocationExpression( root, @@ -138,7 +173,7 @@ private static bool IsArgumentListToken(InvocationExpressionSyntax expression, S out var expression) && currentSpan.Start == SignatureHelpUtilities.GetSignatureHelpSpan(expression.ArgumentList).Start) { - return SignatureHelpUtilities.GetSignatureHelpState(expression.ArgumentList, position); + return SignatureHelpUtilities.GetSignatureHelpState(expression.ArgumentList, position, parameterIndex); } return null; diff --git a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_DelegateAndFunctionPointerInvoke.cs b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_DelegateAndFunctionPointerInvoke.cs index 4f9fb65c869ef..e6d79c993d753 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_DelegateAndFunctionPointerInvoke.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_DelegateAndFunctionPointerInvoke.cs @@ -16,11 +16,10 @@ namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp { internal partial class InvocationExpressionSignatureHelpProviderBase { - private static IList? GetDelegateInvokeItems( - InvocationExpressionSyntax invocationExpression, SemanticModel semanticModel, IStructuralTypeDisplayService structuralTypeDisplayService, - IDocumentationCommentFormattingService documentationCommentFormattingService, ISymbol within, INamedTypeSymbol delegateType, out int? selectedItem, CancellationToken cancellationToken) + private static IMethodSymbol? GetDelegateInvokeMethod( + InvocationExpressionSyntax invocationExpression, SemanticModel semanticModel, ISymbol within, + INamedTypeSymbol delegateType, CancellationToken cancellationToken) { - selectedItem = null; var invokeMethod = delegateType.DelegateInvokeMethod; if (invokeMethod == null) { @@ -35,14 +34,7 @@ internal partial class InvocationExpressionSignatureHelpProviderBase return null; } - return GetDelegateOrFunctionPointerInvokeItems(invocationExpression, invokeMethod, semanticModel, structuralTypeDisplayService, documentationCommentFormattingService, out selectedItem, cancellationToken); - } - - private static IList GetFunctionPointerInvokeItems( - InvocationExpressionSyntax invocationExpression, SemanticModel semanticModel, IStructuralTypeDisplayService structuralTypeDisplayService, - IDocumentationCommentFormattingService documentationCommentFormattingService, IFunctionPointerTypeSymbol functionPointerType, out int? selectedItem, CancellationToken cancellationToken) - { - return GetDelegateOrFunctionPointerInvokeItems(invocationExpression, functionPointerType.Signature, semanticModel, structuralTypeDisplayService, documentationCommentFormattingService, out selectedItem, cancellationToken); + return invokeMethod; } private static IList GetDelegateOrFunctionPointerInvokeItems(InvocationExpressionSyntax invocationExpression, IMethodSymbol invokeMethod, SemanticModel semanticModel, IStructuralTypeDisplayService structuralTypeDisplayService, IDocumentationCommentFormattingService documentationCommentFormattingService, out int? selectedItem, CancellationToken cancellationToken) diff --git a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_MethodGroup.cs b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_MethodGroup.cs index 7c2acff9d63f6..d21eaba3707d0 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_MethodGroup.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProviderBase_MethodGroup.cs @@ -22,12 +22,13 @@ internal partial class InvocationExpressionSignatureHelpProviderBase Document document, InvocationExpressionSyntax invocationExpression, SemanticModel semanticModel, - SymbolInfo currentSymbol, + SymbolInfo symbolInfo, + IMethodSymbol? currentSymbol, CancellationToken cancellationToken) { return Task.FromResult( (accessibleMethods.SelectAsArray(m => ConvertMethodGroupMethod(document, m, invocationExpression.SpanStart, semanticModel)), - TryGetSelectedIndex(accessibleMethods, currentSymbol.Symbol))); + TryGetSelectedIndex(accessibleMethods, currentSymbol))); } private static ImmutableArray GetAccessibleMethods( diff --git a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.cs index bb50d2e0cfbdf..828a490ecd9ee 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.cs @@ -3,7 +3,10 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using System.Composition; +using System.Diagnostics; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -13,6 +16,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp { @@ -54,7 +58,8 @@ private static bool IsArgumentListToken(BaseObjectCreationExpressionSyntax expre protected override async Task GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, SignatureHelpOptions options, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - if (!TryGetObjectCreationExpression(root, position, document.GetRequiredLanguageService(), triggerInfo.TriggerReason, cancellationToken, out var objectCreationExpression)) + if (!TryGetObjectCreationExpression(root, position, document.GetRequiredLanguageService(), triggerInfo.TriggerReason, cancellationToken, out var objectCreationExpression) + || objectCreationExpression.ArgumentList is null) { return null; } @@ -71,20 +76,72 @@ private static bool IsArgumentListToken(BaseObjectCreationExpressionSyntax expre return null; } - var structuralTypeDisplayService = document.GetRequiredLanguageService(); + var symbolDisplayService = document.GetLanguageService(); + if (type.TypeKind == TypeKind.Delegate) + { + return await GetItemsWorkerForDelegateAsync(document, position, objectCreationExpression, type, cancellationToken).ConfigureAwait(false); + } + + // get the candidate methods + var methods = type.InstanceConstructors + .WhereAsArray(c => c.IsAccessibleWithin(within)) + .WhereAsArray(s => s.IsEditorBrowsable(options.HideAdvancedMembers, semanticModel.Compilation)) + .Sort(semanticModel, objectCreationExpression.SpanStart); + + if (!methods.Any()) + { + return null; + } + + // guess the best candidate if needed and determine parameter index + var arguments = objectCreationExpression.ArgumentList.Arguments; + var candidates = semanticModel.GetSymbolInfo(objectCreationExpression, cancellationToken).Symbol is IMethodSymbol exactMatch + ? ImmutableArray.Create(exactMatch) + : methods; + LightweightOverloadResolution.RefineOverloadAndPickParameter(document, position, semanticModel, methods, arguments, out var currentSymbol, out var parameterIndex); + + // present items and select + var structuralTypeDisplayService = document.Project.LanguageServices.GetRequiredService(); var documentationCommentFormattingService = document.GetRequiredLanguageService(); - var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(objectCreationExpression.ArgumentList!); + + var items = methods.SelectAsArray(c => + ConvertNormalTypeConstructor(c, objectCreationExpression, semanticModel, structuralTypeDisplayService, documentationCommentFormattingService)); + + var selectedItem = TryGetSelectedIndex(methods, currentSymbol); + + var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(objectCreationExpression.ArgumentList); var syntaxFacts = document.GetRequiredLanguageService(); + return CreateSignatureHelpItems(items, textSpan, GetCurrentArgumentState(root, position, parameterIndex, syntaxFacts, textSpan, cancellationToken), selectedItem); + } - var (items, selectedItem) = type.TypeKind == TypeKind.Delegate - ? GetDelegateTypeConstructors(objectCreationExpression, semanticModel, structuralTypeDisplayService, type) - : GetNormalTypeConstructors(objectCreationExpression, semanticModel, structuralTypeDisplayService, documentationCommentFormattingService, type, within, options, cancellationToken); + private async Task GetItemsWorkerForDelegateAsync(Document document, int position, BaseObjectCreationExpressionSyntax objectCreationExpression, + INamedTypeSymbol type, CancellationToken cancellationToken) + { + var semanticModel = await document.ReuseExistingSpeculativeModelAsync(objectCreationExpression, cancellationToken).ConfigureAwait(false); + Debug.Assert(type.TypeKind == TypeKind.Delegate); + Debug.Assert(objectCreationExpression.ArgumentList is not null); - return CreateSignatureHelpItems(items, textSpan, - GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken), selectedItem); + var invokeMethod = type.DelegateInvokeMethod; + if (invokeMethod is null) + { + return null; + } + + // determine parameter index + var arguments = objectCreationExpression.ArgumentList.Arguments; + var semanticFactsService = document.GetRequiredLanguageService(); + LightweightOverloadResolution.FindParameterIndexIfCompatibleMethod(arguments, invokeMethod, position, semanticModel, semanticFactsService, out var parameterIndex); + + // present item and select + var structuralTypeDisplayService = document.Project.LanguageServices.GetRequiredService(); + var items = ConvertDelegateTypeConstructor(objectCreationExpression, invokeMethod, semanticModel, structuralTypeDisplayService, position); + var textSpan = SignatureHelpUtilities.GetSignatureHelpSpan(objectCreationExpression.ArgumentList); + var syntaxFacts = document.GetRequiredLanguageService(); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + return CreateSignatureHelpItems(items, textSpan, GetCurrentArgumentState(root, position, parameterIndex, syntaxFacts, textSpan, cancellationToken), selectedItem: 0); } - public override SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) + private SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, int parameterIndex, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) { if (TryGetObjectCreationExpression( root, @@ -95,7 +152,7 @@ private static bool IsArgumentListToken(BaseObjectCreationExpressionSyntax expre out var expression) && currentSpan.Start == SignatureHelpUtilities.GetSignatureHelpSpan(expression.ArgumentList!).Start) { - return SignatureHelpUtilities.GetSignatureHelpState(expression.ArgumentList!, position); + return SignatureHelpUtilities.GetSignatureHelpState(expression.ArgumentList!, position, parameterIndex); } return null; diff --git a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs index 4b24320c7c959..4ed27b88307ff 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.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 Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.SignatureHelp; @@ -12,21 +13,16 @@ namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp { internal partial class ObjectCreationExpressionSignatureHelpProvider { - private static (IList? items, int? selectedItem) GetDelegateTypeConstructors( + private static ImmutableArray ConvertDelegateTypeConstructor( BaseObjectCreationExpressionSyntax objectCreationExpression, + IMethodSymbol invokeMethod, SemanticModel semanticModel, IStructuralTypeDisplayService structuralTypeDisplayService, - INamedTypeSymbol delegateType) + int position) { - var invokeMethod = delegateType.DelegateInvokeMethod; - if (invokeMethod == null) - { - return (null, null); - } - - var position = objectCreationExpression.SpanStart; var item = CreateItem( - invokeMethod, semanticModel, position, + invokeMethod, semanticModel, + objectCreationExpression.SpanStart, structuralTypeDisplayService, isVariadic: false, documentationFactory: null, @@ -35,7 +31,7 @@ private static (IList? items, int? selectedItem) GetDelegateT suffixParts: GetDelegateTypePostambleParts(), parameters: GetDelegateTypeParameters(invokeMethod, semanticModel, position)); - return (SpecializedCollections.SingletonList(item), 0); + return ImmutableArray.Create(item); } private static IList GetDelegateTypePreambleParts(IMethodSymbol invokeMethod, SemanticModel semanticModel, int position) diff --git a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs index 26cca60bb2463..73052e9cdcb6b 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; -using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.DocumentationComments; @@ -17,30 +16,6 @@ namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp { internal partial class ObjectCreationExpressionSignatureHelpProvider { - private static (IList items, int? selectedItem) GetNormalTypeConstructors( - BaseObjectCreationExpressionSyntax objectCreationExpression, - SemanticModel semanticModel, - IStructuralTypeDisplayService structuralTypeDisplayService, - IDocumentationCommentFormattingService documentationCommentFormattingService, - INamedTypeSymbol normalType, - ISymbol within, - SignatureHelpOptions options, - CancellationToken cancellationToken) - { - var accessibleConstructors = normalType.InstanceConstructors - .WhereAsArray(c => c.IsAccessibleWithin(within)) - .WhereAsArray(s => s.IsEditorBrowsable(options.HideAdvancedMembers, semanticModel.Compilation)) - .Sort(semanticModel, objectCreationExpression.SpanStart); - - var symbolInfo = semanticModel.GetSymbolInfo(objectCreationExpression, cancellationToken); - var selectedItem = TryGetSelectedIndex(accessibleConstructors, symbolInfo.Symbol); - - var items = accessibleConstructors.SelectAsArray(c => - ConvertNormalTypeConstructor(c, objectCreationExpression, semanticModel, structuralTypeDisplayService, documentationCommentFormattingService)); - - return (items, selectedItem); - } - private static SignatureHelpItem ConvertNormalTypeConstructor( IMethodSymbol constructor, BaseObjectCreationExpressionSyntax objectCreationExpression, diff --git a/src/Features/CSharp/Portable/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProvider.cs index c764f9c7b0bd5..72723f599349a 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/PrimaryConstructorBaseTypeSignatureHelpProvider.cs @@ -100,7 +100,7 @@ private bool IsTriggerToken(SyntaxToken token) textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken), selectedItem); } - public override SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) + private SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) { if (TryGetBaseTypeSyntax(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, out var expression) && currentSpan.Start == SignatureHelpUtilities.GetSignatureHelpSpan(expression.ArgumentList).Start) diff --git a/src/Features/CSharp/Portable/SignatureHelp/SignatureHelpUtilities.cs b/src/Features/CSharp/Portable/SignatureHelp/SignatureHelpUtilities.cs index 46e4c738a3187..319fdf0e8780c 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/SignatureHelpUtilities.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/SignatureHelpUtilities.cs @@ -46,6 +46,17 @@ internal static class SignatureHelpUtilities ? argument.NameColon.Name.Identifier.ValueText : argument.NameEquals?.Name.Identifier.ValueText); + internal static SignatureHelpState? GetSignatureHelpState(BaseArgumentListSyntax argumentList, int position, int parameterIndex) + { + var result = GetSignatureHelpState(argumentList, position); + if (result is not null && parameterIndex >= 0) + { + result.ArgumentIndex = parameterIndex; + } + + return result; + } + internal static SignatureHelpState? GetSignatureHelpState(BaseArgumentListSyntax argumentList, int position) { return CommonSignatureHelpUtilities.GetSignatureHelpState( diff --git a/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs index 4f3dfa14590a9..30074faa069b9 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs @@ -34,7 +34,7 @@ public TupleConstructionSignatureHelpProvider() { } - public override SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) + private SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken) { if (GetOuterMostTupleExpressionInSpan(root, position, syntaxFacts, currentSpan, cancellationToken, out var expression)) { diff --git a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs index 21a5377b6d0ed..f572364f624b5 100644 --- a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs @@ -22,9 +22,6 @@ internal sealed class CSharpSimplifyThisOrMeDiagnosticAnalyzer ThisExpressionSyntax, MemberAccessExpressionSyntax> { - protected override string GetLanguageName() - => LanguageNames.CSharp; - protected override ISyntaxFacts GetSyntaxFacts() => CSharpSyntaxFacts.Instance; diff --git a/src/Features/CSharp/Portable/Snippets/CSharpSnippetFunctionService.cs b/src/Features/CSharp/Portable/Snippets/CSharpSnippetFunctionService.cs new file mode 100644 index 0000000000000..bba4489373c87 --- /dev/null +++ b/src/Features/CSharp/Portable/Snippets/CSharpSnippetFunctionService.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.CSharp; + +[ExportLanguageService(typeof(SnippetFunctionService), LanguageNames.CSharp), Shared] +internal class CSharpSnippetFunctionService : SnippetFunctionService +{ + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpSnippetFunctionService() + { + } + + public override async Task GetContainingClassNameAsync(Document document, int position, CancellationToken cancellationToken) + { + // Find the nearest enclosing type declaration and use its name + var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var type = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken).GetAncestor(); + + return type?.Identifier.ToString(); + } + + protected override async Task GetEnumSymbolAsync(Document document, TextSpan switchExpressionSpan, CancellationToken cancellationToken) + { + var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var token = syntaxTree.FindTokenOnRightOfPosition(switchExpressionSpan.Start, cancellationToken); + var expressionNode = token.GetAncestor(n => n.Span == switchExpressionSpan); + + if (expressionNode == null) + { + return null; + } + + var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var typeSymbol = model.GetTypeInfo(expressionNode, cancellationToken).Type; + + return typeSymbol; + } + + protected override async Task<(Document, TextSpan)> GetDocumentWithEnumCaseAsync( + Document document, + string fullyQualifiedTypeName, + string firstEnumMemberName, + TextSpan caseGenerationLocation, + CancellationToken cancellationToken) + { + var str = "case " + fullyQualifiedTypeName + "." + firstEnumMemberName + ":" + Environment.NewLine + " break;"; + var textChange = new TextChange(caseGenerationLocation, str); + var typeSpan = new TextSpan(caseGenerationLocation.Start + "case ".Length, fullyQualifiedTypeName.Length); + + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var documentWithCaseAdded = document.WithText(text.WithChanges(textChange)); + + return (documentWithCaseAdded, typeSpan); + } + + public override string SwitchCaseFormat => @"case {0}.{1}: + break; +"; + + public override string SwitchDefaultCaseForm => @"default: + break;"; +} diff --git a/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs b/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs index 613900044cd2c..af391391ad71f 100644 --- a/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs +++ b/src/Features/CSharp/Portable/SplitStringLiteral/InterpolatedStringSplitter.cs @@ -20,10 +20,14 @@ private sealed class InterpolatedStringSplitter : StringSplitter private readonly InterpolatedStringExpressionSyntax _interpolatedStringExpression; public InterpolatedStringSplitter( - Document document, int position, - SyntaxNode root, SourceText sourceText, + Document document, + int position, + SyntaxNode root, + SourceText sourceText, InterpolatedStringExpressionSyntax interpolatedStringExpression, - bool useTabs, int tabSize, FormattingOptions.IndentStyle indentStyle, + bool useTabs, + int tabSize, + FormattingOptions.IndentStyle indentStyle, CancellationToken cancellationToken) : base(document, position, root, sourceText, useTabs, tabSize, indentStyle, cancellationToken) { @@ -32,9 +36,9 @@ public InterpolatedStringSplitter( protected override SyntaxNode GetNodeToReplace() => _interpolatedStringExpression; - // Don't offer on $@"" strings. They support newlines directly in their content. + // Don't offer on $@"" strings and raw string literals. They support newlines directly in their content. protected override bool CheckToken() - => _interpolatedStringExpression.StringStartToken.Kind() != SyntaxKind.InterpolatedVerbatimStringStartToken; + => _interpolatedStringExpression.StringStartToken.Kind() == SyntaxKind.InterpolatedStringStartToken; protected override BinaryExpressionSyntax CreateSplitString() { diff --git a/src/Features/CSharp/Portable/StringIndentation/CSharpStringIndentationService.cs b/src/Features/CSharp/Portable/StringIndentation/CSharpStringIndentationService.cs new file mode 100644 index 0000000000000..fead30c3b90b7 --- /dev/null +++ b/src/Features/CSharp/Portable/StringIndentation/CSharpStringIndentationService.cs @@ -0,0 +1,170 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Syntax; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.StringIndentation; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.LineSeparators +{ + [ExportLanguageService(typeof(IStringIndentationService), LanguageNames.CSharp), Shared] + internal class CSharpStringIndentationService : IStringIndentationService + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpStringIndentationService() + { + } + + public async Task> GetStringIndentationRegionsAsync( + Document document, TextSpan textSpan, CancellationToken cancellationToken) + { + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + using var _ = ArrayBuilder.GetInstance(out var result); + + Recurse(text, root, textSpan, result, cancellationToken); + + return result.ToImmutable(); + } + + private void Recurse( + SourceText text, SyntaxNode node, TextSpan textSpan, ArrayBuilder result, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (!node.Span.IntersectsWith(textSpan)) + return; + + if (node.IsKind(SyntaxKind.InterpolatedStringExpression, out InterpolatedStringExpressionSyntax? interpolatedString) && + interpolatedString.StringStartToken.IsKind(SyntaxKind.InterpolatedMultiLineRawStringStartToken)) + { + ProcessInterpolatedStringExpression(text, interpolatedString, result, cancellationToken); + } + + foreach (var child in node.ChildNodesAndTokens()) + { + if (child.IsNode) + Recurse(text, child.AsNode()!, textSpan, result, cancellationToken); + else if (child.IsKind(SyntaxKind.MultiLineRawStringLiteralToken)) + ProcessMultiLineRawStringLiteralToken(text, child.AsToken(), result, cancellationToken); + } + } + + private static void ProcessMultiLineRawStringLiteralToken( + SourceText text, SyntaxToken token, ArrayBuilder result, CancellationToken cancellationToken) + { + // Ignore strings with errors as we don't want to draw a line in a bad place that makes things even harder + // to understand. + if (token.ContainsDiagnostics && token.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)) + return; + + cancellationToken.ThrowIfCancellationRequested(); + if (!TryGetIndentSpan(text, (ExpressionSyntax)token.GetRequiredParent(), out _, out var indentSpan)) + return; + + result.Add(new StringIndentationRegion(indentSpan)); + } + + private static void ProcessInterpolatedStringExpression(SourceText text, InterpolatedStringExpressionSyntax interpolatedString, ArrayBuilder result, CancellationToken cancellationToken) + { + // Ignore strings with errors as we don't want to draw a line in a bad place that makes things even harder + // to understand. + if (interpolatedString.ContainsDiagnostics) + { + var errors = interpolatedString.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error); + foreach (var error in errors) + { + if (!IsInHole(interpolatedString, error.Location.SourceSpan)) + return; + } + } + + cancellationToken.ThrowIfCancellationRequested(); + if (!TryGetIndentSpan(text, interpolatedString, out var offset, out var indentSpan)) + return; + + using var _ = ArrayBuilder.GetInstance(out var builder); + + foreach (var content in interpolatedString.Contents) + { + if (content is InterpolationSyntax interpolation && + !IgnoreInterpolation(text, offset, interpolation)) + { + builder.Add(interpolation.Span); + } + } + + result.Add(new StringIndentationRegion(indentSpan, builder.ToImmutable())); + } + + private static bool IsInHole(InterpolatedStringExpressionSyntax interpolatedString, TextSpan sourceSpan) + { + foreach (var content in interpolatedString.Contents) + { + if (content is InterpolationSyntax && content.Span.Contains(sourceSpan)) + return true; + } + + return false; + } + + private static bool IgnoreInterpolation(SourceText text, int offset, InterpolationSyntax interpolation) + { + // We can ignore the hole if all the content of it is after the region's indentation level. + // In that case, it's fine to draw the line through the hole as it won't intersect any code + // (or show up on the right side of the line). + + var holeStartLine = text.Lines.GetLineFromPosition(interpolation.SpanStart).LineNumber; + var holeEndLine = text.Lines.GetLineFromPosition(interpolation.Span.End).LineNumber; + + for (var i = holeStartLine; i <= holeEndLine; i++) + { + var line = text.Lines[i]; + var currentLineOffset = line.GetFirstNonWhitespaceOffset(); + + if (currentLineOffset != null && currentLineOffset < offset) + return false; + } + + return true; + } + + private static bool TryGetIndentSpan(SourceText text, ExpressionSyntax expression, out int offset, out TextSpan indentSpan) + { + indentSpan = default; + + // get the last line of the literal to determine the indentation string. + var lastLine = text.Lines.GetLineFromPosition(expression.Span.End); + var offsetOpt = lastLine.GetFirstNonWhitespaceOffset(); + + // We should always have a non-null offset in a multi-line raw string without errors. + Contract.ThrowIfNull(offsetOpt); + offset = offsetOpt.Value; + if (offset == 0) + return false; + + var firstLine = text.Lines.GetLineFromPosition(expression.SpanStart); + + // A literal without errors must span at least three lines. Like so: + // """ + // foo + // """ + Contract.ThrowIfTrue(lastLine.LineNumber - firstLine.LineNumber < 2); + indentSpan = TextSpan.FromBounds(firstLine.Start, lastLine.Start + offset); + return true; + } + } +} diff --git a/src/Features/CSharp/Portable/UseAutoProperty/CSharpUseAutoPropertyCodeFixProvider.cs b/src/Features/CSharp/Portable/UseAutoProperty/CSharpUseAutoPropertyCodeFixProvider.cs index e380eb18e88a3..a94b7f7d55509 100644 --- a/src/Features/CSharp/Portable/UseAutoProperty/CSharpUseAutoPropertyCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UseAutoProperty/CSharpUseAutoPropertyCodeFixProvider.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; @@ -157,7 +158,7 @@ private static bool NeedsSetter(Compilation compilation, PropertyDeclarationSynt } private static bool SupportsReadOnlyProperties(Compilation compilation) - => ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp6; + => compilation.LanguageVersion() >= LanguageVersion.CSharp6; private static AccessorListSyntax UpdateAccessorList(AccessorListSyntax accessorList) { diff --git a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs index ddd030b16e87f..7c18d147aada6 100644 --- a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs @@ -106,8 +106,7 @@ private static bool TryComputeRefactoring( succeeded = true; } - var (canOffer, _) = helper.CanOfferUseBlockBody(optionSet, declaration, forAnalyzer: false); - if (canOffer) + if (helper.CanOfferUseBlockBody(optionSet, declaration, forAnalyzer: false, out _, out _)) { context.RegisterRefactoring( new MyCodeAction( @@ -138,7 +137,7 @@ private static async Task UpdateDocumentAsync( UseExpressionBodyHelper helper, bool useExpressionBody, CancellationToken cancellationToken) { - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var updatedDeclaration = helper.Update(semanticModel, declaration, useExpressionBody); var parent = declaration is AccessorDeclarationSyntax diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs index a592fb6d5ce95..0357333fdb241 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs @@ -46,7 +46,7 @@ private static ExpressionSyntax GetBodyAsExpression(LambdaExpressionSyntax decla => declaration.Body as ExpressionSyntax; private static bool CanOfferUseExpressionBody( - ExpressionBodyPreference preference, LambdaExpressionSyntax declaration) + ExpressionBodyPreference preference, LambdaExpressionSyntax declaration, LanguageVersion languageVersion) { var userPrefersExpressionBodies = preference != ExpressionBodyPreference.Never; if (!userPrefersExpressionBodies) @@ -64,20 +64,19 @@ private static bool CanOfferUseExpressionBody( // They don't have an expression body. See if we could convert the block they // have into one. - var options = declaration.SyntaxTree.Options; - return TryConvertToExpressionBody(declaration, options, preference, out _, out _); + return TryConvertToExpressionBody(declaration, languageVersion, preference, out _, out _); } private static bool TryConvertToExpressionBody( LambdaExpressionSyntax declaration, - ParseOptions options, ExpressionBodyPreference conversionPreference, - out ExpressionSyntax expression, out SyntaxToken semicolon) + LanguageVersion languageVersion, + ExpressionBodyPreference conversionPreference, + out ExpressionSyntax expression, + out SyntaxToken semicolon) { var body = declaration.Body as BlockSyntax; - return body.TryConvertToExpressionBody( - options, conversionPreference, - out expression, out semicolon); + return body.TryConvertToExpressionBody(languageVersion, conversionPreference, out expression, out semicolon); } private static bool CanOfferUseBlockBody( @@ -115,7 +114,7 @@ private static bool CanOfferUseBlockBody( return false; } - var languageVersion = ((CSharpParseOptions)declaration.SyntaxTree.Options).LanguageVersion; + var languageVersion = declaration.SyntaxTree.Options.LanguageVersion(); if (expressionBodyOpt.IsKind(SyntaxKind.ThrowExpression) && languageVersion < LanguageVersion.CSharp7) { @@ -134,15 +133,13 @@ private static LambdaExpressionSyntax UpdateWorker( { var expressionBody = GetBodyAsExpression(currentDeclaration); return expressionBody == null - ? WithExpressionBody(currentDeclaration) + ? WithExpressionBody(currentDeclaration, originalDeclaration.GetLanguageVersion()) : WithBlockBody(semanticModel, originalDeclaration, currentDeclaration); } - private static LambdaExpressionSyntax WithExpressionBody(LambdaExpressionSyntax declaration) + private static LambdaExpressionSyntax WithExpressionBody(LambdaExpressionSyntax declaration, LanguageVersion languageVersion) { - if (!TryConvertToExpressionBody( - declaration, declaration.SyntaxTree.Options, ExpressionBodyPreference.WhenPossible, - out var expressionBody, out _)) + if (!TryConvertToExpressionBody(declaration, languageVersion, ExpressionBodyPreference.WhenPossible, out var expressionBody, out _)) { return declaration; } diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Analysis.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Analysis.cs index aff8520c8d660..bb21394dadfff 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Analysis.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Analysis.cs @@ -7,6 +7,7 @@ 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; @@ -38,7 +39,7 @@ private Diagnostic AnalyzeSyntax( SemanticModel semanticModel, CodeStyleOption2 option, LambdaExpressionSyntax declaration, CancellationToken cancellationToken) { - if (CanOfferUseExpressionBody(option.Value, declaration)) + if (CanOfferUseExpressionBody(option.Value, declaration, declaration.GetLanguageVersion())) { var location = GetDiagnosticLocation(declaration); diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs index 4ada48a26f064..a394bfb30fe7b 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -106,7 +107,7 @@ private static async Task> ComputeRefactoringsAsync( var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); using var resultDisposer = ArrayBuilder.GetInstance(out var result); - if (CanOfferUseExpressionBody(option, lambdaNode)) + if (CanOfferUseExpressionBody(option, lambdaNode, root.GetLanguageVersion())) { result.Add(new MyCodeAction( UseExpressionBodyTitle.ToString(), diff --git a/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs b/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs index bc8fb3da24002..19dbb99b310eb 100644 --- a/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -89,7 +90,7 @@ protected override async Task FixAllAsync( var currentRoot = root.TrackNodes(nodesToTrack); var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var languageVersion = ((CSharpParseOptions)semanticModel.SyntaxTree.Options).LanguageVersion; + var languageVersion = semanticModel.SyntaxTree.Options.LanguageVersion(); var makeStaticIfPossible = languageVersion >= LanguageVersion.CSharp8 && options.GetOption(CSharpCodeStyleOptions.PreferStaticLocalFunction).Value; @@ -105,7 +106,7 @@ protected override async Task FixAllAsync( var currentAnonymousFunction = currentRoot.GetCurrentNode(anonymousFunction); currentRoot = ReplaceAnonymousWithLocalFunction( - document.Project.Solution.Workspace, currentRoot, + document.Project.Solution.Workspace.Services, currentRoot, currentLocalDeclaration, currentAnonymousFunction, delegateType.DelegateInvokeMethod, parameterList, makeStatic); @@ -149,7 +150,7 @@ private static bool MakeStatic( } private static SyntaxNode ReplaceAnonymousWithLocalFunction( - Workspace workspace, SyntaxNode currentRoot, + HostWorkspaceServices services, SyntaxNode currentRoot, LocalDeclarationStatementSyntax localDeclaration, AnonymousFunctionExpressionSyntax anonymousFunction, IMethodSymbol delegateMethod, ParameterListSyntax parameterList, bool makeStatic) { @@ -157,7 +158,7 @@ private static SyntaxNode ReplaceAnonymousWithLocalFunction( .WithTriviaFrom(localDeclaration) .WithAdditionalAnnotations(Formatter.Annotation); - var editor = new SyntaxEditor(currentRoot, workspace); + var editor = new SyntaxEditor(currentRoot, services); editor.ReplaceNode(localDeclaration, newLocalFunctionStatement); var anonymousFunctionStatement = anonymousFunction.GetAncestor(); diff --git a/src/Features/CSharp/Portable/UseNamedArguments/CSharpUseNamedArgumentsCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseNamedArguments/CSharpUseNamedArgumentsCodeRefactoringProvider.cs index 307fe5c884f04..6f65b384fd1f9 100644 --- a/src/Features/CSharp/Portable/UseNamedArguments/CSharpUseNamedArgumentsCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseNamedArguments/CSharpUseNamedArgumentsCodeRefactoringProvider.cs @@ -31,7 +31,7 @@ protected sealed override bool IsLegalToAddNamedArguments(ImmutableArray !parameters.Last().IsParams || parameters.Length >= argumentCount; protected override bool SupportsNonTrailingNamedArguments(ParseOptions options) - => ((CSharpParseOptions)options).LanguageVersion >= LanguageVersion.CSharp7_2; + => options.LanguageVersion() >= LanguageVersion.CSharp7_2; protected override bool IsImplicitIndexOrRangeIndexer(ImmutableArray parameters, TSyntax argument, SemanticModel semanticModel) { diff --git a/src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs index 8fd22d2e3a2db..650cf7cd252d3 100644 --- a/src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/UsePatternMatching/CSharpIsAndCastCheckWithoutNameDiagnosticAnalyzer.cs @@ -71,7 +71,7 @@ private void SyntaxNodeAction( // "x is Type y" is only available in C# 7.0 and above. Don't offer this refactoring // in projects targeting a lesser version. - if (((CSharpParseOptions)syntaxTree.Options).LanguageVersion < LanguageVersion.CSharp7) + if (syntaxTree.Options.LanguageVersion() < LanguageVersion.CSharp7) { return; } diff --git a/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs index e25f948a27cab..30bf98435b21d 100644 --- a/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/Wrapping/CSharpWrappingCodeRefactoringProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation 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; @@ -23,7 +21,8 @@ internal class CSharpWrappingCodeRefactoringProvider : AbstractWrappingCodeRefac new CSharpArgumentWrapper(), new CSharpParameterWrapper(), new CSharpBinaryExpressionWrapper(), - new CSharpChainedExpressionWrapper()); + new CSharpChainedExpressionWrapper(), + new CSharpInitializerExpressionWrapper()); [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/AbstractCSharpSeparatedSyntaxListWrapper.cs b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/AbstractCSharpSeparatedSyntaxListWrapper.cs index 6728482ff2922..54dc545f04bf0 100644 --- a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/AbstractCSharpSeparatedSyntaxListWrapper.cs +++ b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/AbstractCSharpSeparatedSyntaxListWrapper.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.CSharp.Indentation; using Microsoft.CodeAnalysis.Wrapping.SeparatedSyntaxList; diff --git a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpArgumentWrapper.cs b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpArgumentWrapper.cs index 8fc81459f781f..fcbcafc1fd4a9 100644 --- a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpArgumentWrapper.cs +++ b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpArgumentWrapper.cs @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Linq; using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -24,10 +24,20 @@ internal partial class CSharpArgumentWrapper protected override string Wrap_every_item => FeaturesResources.Wrap_every_argument; protected override string Wrap_long_list => FeaturesResources.Wrap_long_argument_list; + public override bool Supports_UnwrapGroup_WrapFirst_IndentRest => true; + public override bool Supports_WrapEveryGroup_UnwrapFirst => true; + public override bool Supports_WrapLongGroup_UnwrapFirst => true; + + protected override bool ShouldMoveOpenBraceToNewLine(OptionSet options) + => false; + + protected override bool ShouldMoveCloseBraceToNewLine + => false; + protected override SeparatedSyntaxList GetListItems(BaseArgumentListSyntax listSyntax) => listSyntax.Arguments; - protected override BaseArgumentListSyntax TryGetApplicableList(SyntaxNode node) + protected override BaseArgumentListSyntax? TryGetApplicableList(SyntaxNode node) => node switch { InvocationExpressionSyntax invocationExpression => invocationExpression.ArgumentList, @@ -38,18 +48,23 @@ protected override BaseArgumentListSyntax TryGetApplicableList(SyntaxNode node) }; protected override bool PositionIsApplicable( - SyntaxNode root, int position, - SyntaxNode declaration, BaseArgumentListSyntax listSyntax) + SyntaxNode root, + int position, + SyntaxNode declaration, + bool containsSyntaxError, + BaseArgumentListSyntax listSyntax) { + if (containsSyntaxError) + return false; + var startToken = listSyntax.GetFirstToken(); - if (declaration is InvocationExpressionSyntax or - ElementAccessExpressionSyntax) + if (declaration is InvocationExpressionSyntax or ElementAccessExpressionSyntax) { // If we have something like Foo(...) or this.Foo(...) allow anywhere in the Foo(...) // section. var expr = (declaration as InvocationExpressionSyntax)?.Expression ?? - (declaration as ElementAccessExpressionSyntax).Expression; + ((ElementAccessExpressionSyntax)declaration).Expression; var name = TryGetInvokedName(expr); startToken = name == null ? listSyntax.GetFirstToken() : name.GetFirstToken(); @@ -68,40 +83,32 @@ protected override bool PositionIsApplicable( var endToken = listSyntax.GetLastToken(); var span = TextSpan.FromBounds(startToken.SpanStart, endToken.Span.End); if (!span.IntersectsWith(position)) - { return false; - } // allow anywhere in the arg list, as long we don't end up walking through something // complex like a lambda/anonymous function. var token = root.FindToken(position); - if (token.Parent.Ancestors().Contains(listSyntax)) + if (token.GetRequiredParent().Ancestors().Contains(listSyntax)) { - for (var current = token.Parent; current != listSyntax; current = current.Parent) + for (var current = token.Parent; current != listSyntax; current = current?.Parent) { if (CSharpSyntaxFacts.Instance.IsAnonymousFunctionExpression(current)) - { return false; - } } } return true; } - private static ExpressionSyntax TryGetInvokedName(ExpressionSyntax expr) + private static ExpressionSyntax? TryGetInvokedName(ExpressionSyntax expr) { // `Foo(...)`. Allow up through the 'Foo' portion if (expr is NameSyntax name) - { return name; - } // `this[...]`. Allow up through the 'this' token. if (expr is ThisExpressionSyntax or BaseExpressionSyntax) - { return expr; - } // expr.Foo(...) or expr?.Foo(...) // All up through the 'Foo' portion. diff --git a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpInitializerExpressionWrapper.cs b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpInitializerExpressionWrapper.cs new file mode 100644 index 0000000000000..88cb6940decf4 --- /dev/null +++ b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpInitializerExpressionWrapper.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Options; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Wrapping.SeparatedSyntaxList +{ + internal sealed partial class CSharpInitializerExpressionWrapper + : AbstractCSharpSeparatedSyntaxListWrapper + { + protected override string Indent_all_items => FeaturesResources.Indent_all_elements; + protected override string Unwrap_all_items => FeaturesResources.Unwrap_all_elements; + protected override string Unwrap_list => FeaturesResources.Unwrap_initializer; + protected override string Wrap_every_item => FeaturesResources.Wrap_initializer; + protected override string Wrap_long_list => FeaturesResources.Wrap_long_initializer; + + public override bool Supports_UnwrapGroup_WrapFirst_IndentRest => false; + public override bool Supports_WrapEveryGroup_UnwrapFirst => false; + public override bool Supports_WrapLongGroup_UnwrapFirst => false; + + // unreachable as we explicitly declare that we don't support these scenarios. + + protected override string Align_wrapped_items => throw ExceptionUtilities.Unreachable; + protected override string Indent_wrapped_items => throw ExceptionUtilities.Unreachable; + protected override string Unwrap_and_indent_all_items => throw ExceptionUtilities.Unreachable; + + protected override bool ShouldMoveOpenBraceToNewLine(OptionSet options) + => options.GetOption(CSharpFormattingOptions.NewLinesForBracesInObjectCollectionArrayInitializers); + + protected override bool ShouldMoveCloseBraceToNewLine + => true; + + protected override SeparatedSyntaxList GetListItems(InitializerExpressionSyntax listSyntax) + => listSyntax.Expressions; + + protected override InitializerExpressionSyntax? TryGetApplicableList(SyntaxNode node) + => node as InitializerExpressionSyntax; + + protected override bool PositionIsApplicable(SyntaxNode root, int position, SyntaxNode declaration, bool containsSyntaxError, InitializerExpressionSyntax listSyntax) + { + if (containsSyntaxError) + return false; + + return listSyntax.Span.Contains(position); + } + } +} diff --git a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpParameterWrapper.cs b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpParameterWrapper.cs index 53c9e84d0e2c2..21d9c591c45d3 100644 --- a/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpParameterWrapper.cs +++ b/src/Features/CSharp/Portable/Wrapping/SeparatedSyntaxList/CSharpParameterWrapper.cs @@ -5,7 +5,9 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; @@ -24,6 +26,16 @@ internal partial class CSharpParameterWrapper protected override string Wrap_every_item => FeaturesResources.Wrap_every_parameter; protected override string Wrap_long_list => FeaturesResources.Wrap_long_parameter_list; + public override bool Supports_UnwrapGroup_WrapFirst_IndentRest => true; + public override bool Supports_WrapEveryGroup_UnwrapFirst => true; + public override bool Supports_WrapLongGroup_UnwrapFirst => true; + + protected override bool ShouldMoveOpenBraceToNewLine(OptionSet options) + => false; + + protected override bool ShouldMoveCloseBraceToNewLine + => false; + protected override SeparatedSyntaxList GetListItems(BaseParameterListSyntax listSyntax) => listSyntax.Parameters; @@ -31,14 +43,12 @@ protected override SeparatedSyntaxList GetListItems(BaseParamet => node.GetParameterList(); protected override bool PositionIsApplicable( - SyntaxNode root, int position, SyntaxNode declaration, BaseParameterListSyntax listSyntax) + SyntaxNode root, int position, SyntaxNode declaration, bool containsSyntaxError, BaseParameterListSyntax listSyntax) { // CSharpSyntaxGenerator.GetParameterList synthesizes a parameter list for simple-lambdas. // In that case, we're not applicable in that list. if (declaration.Kind() == SyntaxKind.SimpleLambdaExpression) - { return false; - } var generator = CSharpSyntaxGenerator.Instance; var attributes = generator.GetAttributes(declaration); @@ -52,7 +62,13 @@ protected override bool PositionIsApplicable( var lastToken = listSyntax.GetLastToken(); var headerSpan = TextSpan.FromBounds(firstToken.SpanStart, lastToken.Span.End); - return headerSpan.IntersectsWith(position); + if (!headerSpan.IntersectsWith(position)) + return false; + + if (containsSyntaxError && ContainsOverlappingSyntaxErrror(declaration, headerSpan)) + return false; + + return true; } } } diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf index baaabc7568ed9..8e1c250f2cb80 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf @@ -97,6 +97,16 @@ Převést na metodu + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string Převést na běžný řetězec @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + Povolit v projektu typy odkazů s možnou hodnotou null @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + Výběr nemůže obsahovat globální příkazy. Selection cannot include top-level statements - Selection cannot include top-level statements + Výběr nemůže obsahovat příkazy nejvyšší úrovně. @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + Upozornění: Výraz může mít vedlejší účinky. Význam kódu se může změnit. diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf index 376773309e5cb..212ef71d02aa9 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf @@ -97,6 +97,16 @@ In Methode konvertieren + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string In reguläre Zeichenfolge konvertieren @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + Nullwerte zulassende Verweistypen im Projekt aktivieren @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + Die Auswahl darf keine globalen Anweisungen enthalten. Selection cannot include top-level statements - Selection cannot include top-level statements + Die Auswahl darf keine Anweisungen der obersten Ebene enthalten. @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + Warnung: Der Ausdruck kann Nebeneffekte haben. Die Bedeutung des Codes kann sich ändern. @@ -249,7 +259,7 @@ <member name> = - <Membername> = + <Membername> = @@ -259,7 +269,7 @@ <element name> : - <Elementname> : + <Elementname> : diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf index 7d0fb4a8accbc..25fc7f5ce954f 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf @@ -97,6 +97,16 @@ Convertir al método + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string Convertir en cadena regular @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + Habilitar tipos de referencia que aceptan valores NULL en el proyecto @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + La selección no puede incluir declaraciones globales Selection cannot include top-level statements - Selection cannot include top-level statements + La selección no puede incluir instrucciones de nivel superior @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + Advertencia: la expresión puede tener efectos secundarios. El significado del código puede cambiar. @@ -249,7 +259,7 @@ <member name> = - <nombre> = + <nombre> = @@ -259,7 +269,7 @@ <element name> : - <nombre de elemento> : + <nombre de elemento> : diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf index 84863ce766a93..073f648fc59fe 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf @@ -97,6 +97,16 @@ Convertir en méthode + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string Convertir en chaîne classique @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + Activer les types de référence nullables dans le projet @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + La sélection ne peut pas inclure d'instructions globales Selection cannot include top-level statements - Selection cannot include top-level statements + La sélection ne peut pas inclure d'instructions de niveau supérieur @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + Avertissement : L'expression peut avoir des effets secondaires. La signification du code peut changer. @@ -249,7 +259,7 @@ <member name> = - <nom de membre> = + <nom de membre> = @@ -259,7 +269,7 @@ <element name> : - <nom d'élément> : + <nom d'élément> : diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf index 7fc6cb6f484a8..b5fbcb69dc1b9 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf @@ -97,6 +97,16 @@ Converti in metodo + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string Converti in stringa normale @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + Abilita tipi riferimento nullable nel progetto @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + La selezione non può includere istruzioni globali Selection cannot include top-level statements - Selection cannot include top-level statements + La selezione non può includere istruzioni di primo livello @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + Avviso: l'espressione può avere effetti collaterali. Il significato del codice può cambiare. @@ -249,7 +259,7 @@ <member name> = - <nome membro> = + <nome membro> = @@ -259,7 +269,7 @@ <element name> : - <nome elemento>: + <nome elemento>: diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf index 6672b4f562bbb..b8c685de74763 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf @@ -97,6 +97,16 @@ メソッドに変換 + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string 正規文字列に変換する @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + プロジェクトで null 許容参照型を有効にする @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + 選択にグローバル ステートメントを含めることはできません Selection cannot include top-level statements - Selection cannot include top-level statements + 選択に最上位レベルのステートメントを含めることはできません @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + 警告: 式に副作用がある可能性があります。コードの意味が変更される可能性があります。 @@ -249,7 +259,7 @@ <member name> = - <メンバー名> = + <メンバー名> = @@ -259,7 +269,7 @@ <element name> : - <要素名>: + <要素名> : diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf index f2c7a88d8dfac..7fdc3c60ccf8b 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf @@ -97,6 +97,16 @@ 메서드로 변환 + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string 일반 문자열로 변환 @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + 프로젝트에서 null 허용 참조 형식 사용 @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + 선택 영역에 전체 문을 포함할 수 없습니다. Selection cannot include top-level statements - Selection cannot include top-level statements + 선택 영역에는 최상위 문을 포함할 수 없습니다. @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + 경고: 식에 부작용이 있을 수 있습니다. 코드 의미가 변경될 수 있습니다. @@ -249,7 +259,7 @@ <member name> = - <멤버 이름> = + <멤버 이름> = @@ -259,7 +269,7 @@ <element name> : - <요소 이름>: + <요소 이름>: diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf index 408b6b1e82f9b..577b1b9d0643d 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf @@ -97,6 +97,16 @@ Konwertuj na metodę + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string Konwertuj na zwykły ciąg @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + Włącz typy referencyjne dopuszczające wartości null w projekcie @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + Zaznaczenie nie może zawierać instrukcji globalnych Selection cannot include top-level statements - Selection cannot include top-level statements + Zaznaczenie nie może zawierać instrukcji najwyższego poziomu @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + Ostrzeżenie: wyrażenie może mieć efekty uboczne. Znaczenie kodu może ulec zmianie. diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf index 8ed10a0406553..e1b357e99a54f 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf @@ -97,6 +97,16 @@ Converter em método + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string Converter para cadeia de caracteres regular @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + Habilitar os tipos de referência anuláveis no projeto @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + A seleção não pode incluir instruções globais Selection cannot include top-level statements - Selection cannot include top-level statements + A seleção não pode incluir instruções de nível superior @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + Aviso: A expressão pode ter efeitos colaterais. O significado do código pode alterar. @@ -249,7 +259,7 @@ <member name> = - <nome do membro> = + <nome do membro> = @@ -259,7 +269,7 @@ <element name> : - <nome do elemento> : + <nome do elemento> : diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf index e68bc8ca82658..143a0db468755 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf @@ -97,6 +97,16 @@ Преобразовать в метод + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string Преобразовать в обычную строку @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + Включить типы ссылок, допускающие значение NULL, в проекте @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + Выбор не может включать глобальные операторы Selection cannot include top-level statements - Selection cannot include top-level statements + Выбор не может включать операторы верхнего уровня @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + Внимание! Выражение может иметь побочные эффекты. Значение кода может измениться. @@ -699,7 +709,7 @@ <interface name> - < имя интерфейса > + <имя интерфейса> diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf index 457212e20619c..91a4a82fc5c10 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf @@ -97,6 +97,16 @@ Yönteme dönüştür + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string Normal dizeye dönüştür @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + Projedeki null atanabilir başvuru türlerini etkinleştir @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + Seçim genel deyimleri içeremez Selection cannot include top-level statements - Selection cannot include top-level statements + Seçim en üst düzey deyimleri içeremez @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + Uyarı: İfadenin yan etkileri olabilir. Kod anlamı değişebilir. @@ -234,7 +244,7 @@ <lambda expression> - < lambda ifadesi > + <lambda ifadesi> @@ -249,7 +259,7 @@ <member name> = - < üye adı > = + <üye adı> = @@ -259,7 +269,7 @@ <element name> : - < öğe adı >: + <öğe adı>: @@ -274,7 +284,7 @@ <range variable> - < Aralık değişkeni > + <Aralık değişkeni> @@ -669,7 +679,7 @@ <namespace name> - < ad alanı adı > + <ad alanı adı> @@ -694,22 +704,22 @@ <class name> - < sınıf adı > + <sınıf adı> <interface name> - < arabirim adı > + <arabirim adı> <designation name> - < atama adı > + <atama adı> <struct name> - < yapı adı > + <yapı adı> @@ -724,7 +734,7 @@ <Name> - < ad > + <ad> diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf index 896d35ecbaed4..38daa1b0c923a 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf @@ -97,6 +97,16 @@ 转换为方法 + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string 转换为正则字符串 @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + 在项目中启用可为 null 的引用类型 @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + 所选内容不能包含全局语句 Selection cannot include top-level statements - Selection cannot include top-level statements + 所选内容不能包含顶级语句 @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + 警告: 表达式可能有副作用。代码含义可能更改。 @@ -249,7 +259,7 @@ <member name> = - <成员名称> = + <成员名称>= @@ -259,7 +269,7 @@ <element name> : - <元素名称>: + <元素名称>: diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf index 9cc8236bb002c..ef69480d435f2 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf @@ -97,6 +97,16 @@ 轉換為方法 + + Convert to raw string + Convert to raw string + + + + Convert to raw string (no indent) + Convert to raw string (no indent) + + Convert to regular string 轉換為一般字串 @@ -124,7 +134,7 @@ Enable nullable reference types in project - Enable nullable reference types in project + 在專案中啟用可為 Null 的參考類型 @@ -169,12 +179,12 @@ Selection cannot include global statements - Selection cannot include global statements + 選取範圍不能包含全域陳述式 Selection cannot include top-level statements - Selection cannot include top-level statements + 選取範圍不能包含最上層陳述式 @@ -204,7 +214,7 @@ Warning: Expression may have side effects. Code meaning may change. - Warning: Expression may have side effects. Code meaning may change. + 警告: 運算式可能有副作用。代碼意義可能變更。 @@ -249,7 +259,7 @@ <member name> = - <成員名稱> = + <成員名稱>= @@ -259,7 +269,7 @@ <element name> : - <元素名稱> : + <元素名稱>: diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs index 6d73aa2eb24f2..7fbb15e834188 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs @@ -47,22 +47,29 @@ public AddConstructorParametersCodeAction( _useSubMenuName = useSubMenuName; } - protected override Task GetChangedDocumentAsync(CancellationToken cancellationToken) + protected override async Task GetChangedSolutionAsync(CancellationToken cancellationToken) { - var workspace = _document.Project.Solution.Workspace; + var services = _document.Project.Solution.Workspace.Services; var declarationService = _document.GetRequiredLanguageService(); var constructor = declarationService.GetDeclarations( _constructorCandidate.Constructor).Select(r => r.GetSyntax(cancellationToken)).First(); + var codeGenerator = _document.GetRequiredLanguageService(); + var options = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, _document, cancellationToken).ConfigureAwait(false); + var newConstructor = constructor; - newConstructor = CodeGenerator.AddParameterDeclarations(newConstructor, _missingParameters, workspace); - newConstructor = CodeGenerator.AddStatements(newConstructor, CreateAssignStatements(_constructorCandidate), workspace) + newConstructor = codeGenerator.AddParameters(newConstructor, _missingParameters, options, cancellationToken); + newConstructor = codeGenerator.AddStatements(newConstructor, CreateAssignStatements(_constructorCandidate), options, cancellationToken) .WithAdditionalAnnotations(Formatter.Annotation); var syntaxTree = constructor.SyntaxTree; var newRoot = syntaxTree.GetRoot(cancellationToken).ReplaceNode(constructor, newConstructor); - return Task.FromResult(_document.WithSyntaxRoot(newRoot)); + // Make sure we get the document that contains the constructor we just updated + var constructorDocument = _document.Project.GetDocument(syntaxTree); + Contract.ThrowIfNull(constructorDocument); + + return constructorDocument.WithSyntaxRoot(newRoot).Project.Solution; } private IEnumerable CreateAssignStatements(ConstructorCandidate constructorCandidate) diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs index c95ac538f132f..2898b6e120849 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.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.Composition; using System.Diagnostics.CodeAnalysis; @@ -13,6 +14,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Features.Intents; using Microsoft.CodeAnalysis.GenerateFromMembers; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -28,7 +30,7 @@ namespace Microsoft.CodeAnalysis.AddConstructorParametersFromMembers internal partial class AddConstructorParametersFromMembersCodeRefactoringProvider : AbstractGenerateFromMembersCodeRefactoringProvider, IIntentProvider { [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public AddConstructorParametersFromMembersCodeRefactoringProvider() { } diff --git a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs index 38327967a7173..261c20b40f164 100644 --- a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs @@ -113,7 +113,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); + var editor = new SyntaxEditor(syntaxRoot, document.Project.Solution.Workspace.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 58e170da43ef3..5744c0ab94899 100644 --- a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs @@ -124,7 +124,7 @@ private ImmutableArray UpdateEmbeddedFileNames( } private async Task> TryGetBannerAsync( - Document document, SyntaxNode root, CancellationToken cancellationToken) + Document document, SyntaxNode? root, CancellationToken cancellationToken) { var bannerService = document.GetRequiredLanguageService(); var syntaxFacts = document.GetRequiredLanguageService(); diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index d08056166d630..25fcf19a4d6f3 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -18,15 +16,15 @@ internal abstract partial class AbstractAddImportCodeFixProvider : CodeFixProvid { private const int MaxResults = 5; - private readonly IPackageInstallerService _packageInstallerService; - private readonly ISymbolSearchService _symbolSearchService; + private readonly IPackageInstallerService? _packageInstallerService; + private readonly ISymbolSearchService? _symbolSearchService; /// /// Values for these parameters can be provided (during testing) for mocking purposes. /// protected AbstractAddImportCodeFixProvider( - IPackageInstallerService packageInstallerService = null, - ISymbolSearchService symbolSearchService = null) + IPackageInstallerService? packageInstallerService = null, + ISymbolSearchService? symbolSearchService = null) { _packageInstallerService = packageInstallerService; _symbolSearchService = symbolSearchService; @@ -40,7 +38,7 @@ protected AbstractAddImportCodeFixProvider( private protected override CodeActionRequestPriority ComputeRequestPriority() => CodeActionRequestPriority.High; - public sealed override FixAllProvider GetFixAllProvider() + public sealed override FixAllProvider? GetFixAllProvider() { // Currently Fix All is not supported for this provider // https://github.com/dotnet/roslyn/issues/34457 @@ -54,25 +52,34 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var cancellationToken = context.CancellationToken; var diagnostics = context.Diagnostics; - var addImportService = document.GetLanguageService(); + var addImportService = document.GetRequiredLanguageService(); + var services = document.Project.Solution.Workspace.Services; - var solution = document.Project.Solution; - var options = solution.Options; + var searchOptions = context.Options.SearchOptions; - var searchReferenceAssemblies = options.GetOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, document.Project.Language); - var searchNuGetPackages = options.GetOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages, document.Project.Language); + var symbolSearchService = _symbolSearchService ?? services.GetRequiredService(); - var symbolSearchService = searchReferenceAssemblies || searchNuGetPackages - ? _symbolSearchService ?? solution.Workspace.Services.GetService() - : null; + var installerService = searchOptions.SearchNuGetPackages ? + _packageInstallerService ?? services.GetService() : null; - var installerService = GetPackageInstallerService(document); - var packageSources = searchNuGetPackages && symbolSearchService != null && installerService?.IsEnabled(document.Project.Id) == true + var packageSources = installerService?.IsEnabled(document.Project.Id) == true ? installerService.TryGetPackageSources() : ImmutableArray.Empty; + if (packageSources.IsEmpty) + { + searchOptions = searchOptions with { SearchNuGetPackages = false }; + } + + var placement = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + + var addImportOptions = new AddImportOptions( + searchOptions, + context.Options.HideAdvancedMembers, + placement); + var fixesForDiagnostic = await addImportService.GetFixesForDiagnosticsAsync( - document, span, diagnostics, MaxResults, symbolSearchService, searchReferenceAssemblies, packageSources, cancellationToken).ConfigureAwait(false); + document, span, diagnostics, MaxResults, symbolSearchService, addImportOptions, packageSources, cancellationToken).ConfigureAwait(false); foreach (var (diagnostic, fixes) in fixesForDiagnostic) { @@ -81,8 +88,5 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) context.RegisterFixes(codeActions, diagnostic); } } - - private IPackageInstallerService GetPackageInstallerService(Document document) - => _packageInstallerService ?? document.Project.Solution.Workspace.Services.GetService(); } } diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs index c0cc1aaf35ae1..846831175ea7e 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs @@ -11,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServices; @@ -23,6 +22,7 @@ using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; +using Microsoft.CodeAnalysis.CodeGeneration; namespace Microsoft.CodeAnalysis.AddImport { @@ -45,18 +45,17 @@ internal abstract partial class AbstractAddImportFeatureService AddImportAsync(SyntaxNode contextNode, INamespaceOrTypeSymbol symbol, Document document, bool allowInHiddenRegions, CancellationToken cancellationToken); - protected abstract Task AddImportAsync(SyntaxNode contextNode, IReadOnlyList nameSpaceParts, Document document, bool allowInHiddenRegions, CancellationToken cancellationToken); + protected abstract Task AddImportAsync(SyntaxNode contextNode, INamespaceOrTypeSymbol symbol, Document document, AddImportPlacementOptions options, CancellationToken cancellationToken); + protected abstract Task AddImportAsync(SyntaxNode contextNode, IReadOnlyList nameSpaceParts, Document document, AddImportPlacementOptions options, CancellationToken cancellationToken); protected abstract bool IsAddMethodContext(SyntaxNode node, SemanticModel semanticModel); protected abstract string GetDescription(IReadOnlyList nameParts); - protected abstract (string description, bool hasExistingImport) GetDescription(Document document, OptionSet options, INamespaceOrTypeSymbol symbol, SemanticModel semanticModel, SyntaxNode root, CancellationToken cancellationToken); + protected abstract (string description, bool hasExistingImport) GetDescription(Document document, AddImportPlacementOptions options, INamespaceOrTypeSymbol symbol, SemanticModel semanticModel, SyntaxNode root, CancellationToken cancellationToken); public async Task> GetFixesAsync( Document document, TextSpan span, string diagnosticId, int maxResults, - bool allowInHiddenRegions, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); @@ -65,7 +64,7 @@ public async Task> GetFixesAsync( var result = await client.TryInvokeAsync>( document.Project.Solution, (service, solutionInfo, callbackId, cancellationToken) => - service.GetFixesAsync(solutionInfo, callbackId, document.Id, span, diagnosticId, maxResults, allowInHiddenRegions, searchReferenceAssemblies, packageSources, cancellationToken), + service.GetFixesAsync(solutionInfo, callbackId, document.Id, span, diagnosticId, maxResults, options, packageSources, cancellationToken), callbackTarget: symbolSearchService, cancellationToken).ConfigureAwait(false); @@ -74,15 +73,13 @@ public async Task> GetFixesAsync( return await GetFixesInCurrentProcessAsync( document, span, diagnosticId, maxResults, - allowInHiddenRegions, - symbolSearchService, searchReferenceAssemblies, + symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); } private async Task> GetFixesInCurrentProcessAsync( Document document, TextSpan span, string diagnosticId, int maxResults, - bool allowInHiddenRegions, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -97,19 +94,19 @@ private async Task> GetFixesInCurrentProcessAsy { if (!cancellationToken.IsCancellationRequested) { - if (CanAddImport(node, allowInHiddenRegions, cancellationToken)) + if (CanAddImport(node, options.Placement.AllowInHiddenRegions, cancellationToken)) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var allSymbolReferences = await FindResultsAsync( document, semanticModel, diagnosticId, node, maxResults, symbolSearchService, - searchReferenceAssemblies, packageSources, cancellationToken).ConfigureAwait(false); + options, packageSources, cancellationToken).ConfigureAwait(false); // Nothing found at all. No need to proceed. foreach (var reference in allSymbolReferences) { cancellationToken.ThrowIfCancellationRequested(); - var fixData = await reference.TryGetFixDataAsync(document, node, allowInHiddenRegions, cancellationToken).ConfigureAwait(false); + var fixData = await reference.TryGetFixDataAsync(document, node, options.Placement, cancellationToken).ConfigureAwait(false); result.AddIfNotNull(fixData); } } @@ -122,7 +119,7 @@ private async Task> GetFixesInCurrentProcessAsy private async Task> FindResultsAsync( Document document, SemanticModel semanticModel, string diagnosticId, SyntaxNode node, int maxResults, ISymbolSearchService symbolSearchService, - bool searchReferenceAssemblies, ImmutableArray packageSources, CancellationToken cancellationToken) + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { // Caches so we don't produce the same data multiple times while searching // all over the solution. @@ -132,7 +129,7 @@ private async Task> FindResultsAsync( var finder = new SymbolReferenceFinder( this, document, semanticModel, diagnosticId, node, symbolSearchService, - searchReferenceAssemblies, packageSources, cancellationToken); + options, packageSources, cancellationToken); // Look for exact matches first: var exactReferences = await FindResultsAsync(projectToAssembly, referenceToCompilation, project, maxResults, finder, exact: true, cancellationToken: cancellationToken).ConfigureAwait(false); @@ -488,25 +485,19 @@ private static bool NotNull(SymbolReference reference) public async Task Fixes)>> GetFixesForDiagnosticsAsync( Document document, TextSpan span, ImmutableArray diagnostics, int maxResultsPerDiagnostic, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { // We might have multiple different diagnostics covering the same span. Have to // process them all as we might produce different fixes for each diagnostic. - // Normally we don't allow generation into a hidden region in the file. However, if we have a - // modern span mapper at our disposal, we do allow it as that host span mapper can handle mapping - // our edit to their domain appropriate. - var allowInHiddenRegions = document.CanAddImportsInHiddenRegions(); - var fixesForDiagnosticBuilder = ArrayBuilder<(Diagnostic, ImmutableArray)>.GetInstance(); foreach (var diagnostic in diagnostics) { var fixes = await GetFixesAsync( document, span, diagnostic.Id, maxResultsPerDiagnostic, - allowInHiddenRegions, - symbolSearchService, searchReferenceAssemblies, + symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); fixesForDiagnosticBuilder.Add((diagnostic, fixes)); @@ -517,7 +508,7 @@ private static bool NotNull(SymbolReference reference) public async Task> GetUniqueFixesAsync( Document document, TextSpan span, ImmutableArray diagnosticIds, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); @@ -526,7 +517,7 @@ public async Task> GetUniqueFixesAsync( var result = await client.TryInvokeAsync>( document.Project.Solution, (service, solutionInfo, callbackId, cancellationToken) => - service.GetUniqueFixesAsync(solutionInfo, callbackId, document.Id, span, diagnosticIds, searchReferenceAssemblies, packageSources, cancellationToken), + service.GetUniqueFixesAsync(solutionInfo, callbackId, document.Id, span, diagnosticIds, options, packageSources, cancellationToken), callbackTarget: symbolSearchService, cancellationToken).ConfigureAwait(false); @@ -535,7 +526,7 @@ public async Task> GetUniqueFixesAsync( return await GetUniqueFixesAsyncInCurrentProcessAsync( document, span, diagnosticIds, - symbolSearchService, searchReferenceAssemblies, + symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); } @@ -544,12 +535,10 @@ private async Task> GetUniqueFixesAsyncInCurren TextSpan span, ImmutableArray diagnosticIds, ISymbolSearchService symbolSearchService, - bool searchReferenceAssemblies, + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { - var allowInHiddenRegions = document.CanAddImportsInHiddenRegions(); - var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); // Get the diagnostics that indicate a missing import. @@ -561,7 +550,7 @@ private async Task> GetUniqueFixesAsyncInCurren .GroupBy(diagnostic => diagnostic.Location.SourceSpan) .Select(diagnosticsForSourceSpan => GetFixesForDiagnosticsAsync( document, diagnosticsForSourceSpan.Key, diagnosticsForSourceSpan.AsImmutable(), - maxResultsPerDiagnostic: 2, symbolSearchService, searchReferenceAssemblies, packageSources, cancellationToken)); + maxResultsPerDiagnostic: 2, symbolSearchService, options, packageSources, cancellationToken)); using var _ = ArrayBuilder.GetInstance(out var fixes); foreach (var getFixesForDiagnosticsTask in getFixesForDiagnosticsTasks) diff --git a/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs index d46eae6061bea..453c8a89cd5c8 100644 --- a/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs +++ b/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -13,6 +14,12 @@ namespace Microsoft.CodeAnalysis.AddImport { + [DataContract] + internal readonly record struct AddImportOptions( + [property: DataMember(Order = 0)] SymbolSearchOptions SearchOptions, + [property: DataMember(Order = 1)] bool HideAdvancedMembers, + [property: DataMember(Order = 2)] AddImportPlacementOptions Placement); + internal interface IAddImportFeatureService : ILanguageService { /// @@ -21,8 +28,7 @@ internal interface IAddImportFeatureService : ILanguageService /// Task> GetFixesAsync( Document document, TextSpan span, string diagnosticId, int maxResults, - bool allowInHiddenRegions, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); /// @@ -31,7 +37,7 @@ Task> GetFixesAsync( /// Task Fixes)>> GetFixesForDiagnosticsAsync( Document document, TextSpan span, ImmutableArray diagnostics, int maxResultsPerDiagnostic, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); /// @@ -44,12 +50,12 @@ ImmutableArray GetCodeActionsForFixes( /// /// Gets data for how to fix a particular id within the specified Document. - /// Similar to + /// Similar to /// except it only returns fix data when there is a single using fix for a given span /// Task> GetUniqueFixesAsync( Document document, TextSpan span, ImmutableArray diagnosticIds, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs b/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs index 7969ee865d58d..680218405a222 100644 --- a/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs +++ b/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.SymbolSearch; using Roslyn.Utilities; @@ -27,10 +28,9 @@ public AssemblyReference( } public override async Task TryGetFixDataAsync( - Document document, SyntaxNode node, bool allowInHiddenRegions, CancellationToken cancellationToken) + Document document, SyntaxNode node, AddImportPlacementOptions options, CancellationToken cancellationToken) { - var textChanges = await GetTextChangesAsync( - document, node, allowInHiddenRegions, cancellationToken).ConfigureAwait(false); + var textChanges = await GetTextChangesAsync(document, node, options, cancellationToken).ConfigureAwait(false); var title = $"{provider.GetDescription(SearchResult.NameParts)} ({string.Format(FeaturesResources.from_0, _referenceAssemblyWithType.AssemblyName)})"; var fullyQualifiedTypeName = string.Join( diff --git a/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs b/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs index 30674ecb28b21..1671105787b8a 100644 --- a/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs @@ -9,7 +9,7 @@ using System.IO; using System.Threading; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -41,7 +41,7 @@ public MetadataSymbolReference( protected override bool ShouldAddWithExistingImport(Document document) => true; protected override (string description, bool hasExistingImport) GetDescription( - Document document, OptionSet options, SyntaxNode node, + Document document, AddImportPlacementOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { var (description, hasExistingImport) = base.GetDescription(document, options, node, semanticModel, cancellationToken); diff --git a/src/Features/Core/Portable/AddImport/References/PackageReference.cs b/src/Features/Core/Portable/AddImport/References/PackageReference.cs index 660979d621cc9..0168a9f3d3830 100644 --- a/src/Features/Core/Portable/AddImport/References/PackageReference.cs +++ b/src/Features/Core/Portable/AddImport/References/PackageReference.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeGeneration; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.AddImport @@ -32,10 +33,10 @@ public PackageReference( } public override async Task TryGetFixDataAsync( - Document document, SyntaxNode node, bool allowInHiddenRegions, CancellationToken cancellationToken) + Document document, SyntaxNode node, AddImportPlacementOptions options, CancellationToken cancellationToken) { var textChanges = await GetTextChangesAsync( - document, node, allowInHiddenRegions, cancellationToken).ConfigureAwait(false); + document, node, options, cancellationToken).ConfigureAwait(false); return AddImportFixData.CreateForPackageSymbol( textChanges, _source, _packageName, _versionOpt); diff --git a/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs b/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs index dd4f15c19888b..3f85b7457f2f8 100644 --- a/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; @@ -86,7 +87,7 @@ protected override AddImportFixData GetFixData( } protected override (string description, bool hasExistingImport) GetDescription( - Document document, OptionSet options, SyntaxNode node, + Document document, AddImportPlacementOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { var (description, hasExistingImport) = base.GetDescription(document, options, node, semanticModel, cancellationToken); diff --git a/src/Features/Core/Portable/AddImport/References/Reference.cs b/src/Features/Core/Portable/AddImport/References/Reference.cs index 77a21a552758d..98dbb57fa3853 100644 --- a/src/Features/Core/Portable/AddImport/References/Reference.cs +++ b/src/Features/Core/Portable/AddImport/References/Reference.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -101,10 +102,10 @@ public override int GetHashCode() } public abstract Task TryGetFixDataAsync( - Document document, SyntaxNode node, bool allowInHiddenRegions, CancellationToken cancellationToken); + Document document, SyntaxNode node, AddImportPlacementOptions options, CancellationToken cancellationToken); protected async Task> GetTextChangesAsync( - Document document, SyntaxNode node, bool allowInHiddenRegions, CancellationToken cancellationToken) + Document document, SyntaxNode node, AddImportPlacementOptions options, CancellationToken cancellationToken) { var originalDocument = document; @@ -112,7 +113,7 @@ protected async Task> GetTextChangesAsync( node, document, cancellationToken).ConfigureAwait(false); var newDocument = await provider.AddImportAsync( - node, SearchResult.NameParts, document, allowInHiddenRegions, cancellationToken).ConfigureAwait(false); + node, SearchResult.NameParts, document, options, cancellationToken).ConfigureAwait(false); var cleanedDocument = await CodeAction.CleanupDocumentAsync( newDocument, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/AddImport/References/SymbolReference.cs b/src/Features/Core/Portable/AddImport/References/SymbolReference.cs index e8b90b1f28262..45f8cf54a43f6 100644 --- a/src/Features/Core/Portable/AddImport/References/SymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/SymbolReference.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -52,7 +52,7 @@ public override int GetHashCode() private async Task> GetTextChangesAsync( Document document, SyntaxNode contextNode, - bool allowInHiddenRegions, bool hasExistingImport, + AddImportPlacementOptions options, bool hasExistingImport, CancellationToken cancellationToken) { // Defer to the language to add the actual import/using. @@ -66,7 +66,7 @@ private async Task> GetTextChangesAsync( var updatedDocument = await provider.AddImportAsync( newContextNode, SymbolResult.Symbol, newDocument, - allowInHiddenRegions, cancellationToken).ConfigureAwait(false); + options, cancellationToken).ConfigureAwait(false); var cleanedDocument = await CodeAction.CleanupDocumentAsync( updatedDocument, cancellationToken).ConfigureAwait(false); @@ -79,9 +79,8 @@ private async Task> GetTextChangesAsync( public sealed override async Task TryGetFixDataAsync( Document document, SyntaxNode node, - bool allowInHiddenRegions, CancellationToken cancellationToken) + AddImportPlacementOptions options, CancellationToken cancellationToken) { - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var (description, hasExistingImport) = GetDescription(document, options, node, semanticModel, cancellationToken); if (description == null) @@ -114,7 +113,7 @@ public sealed override async Task TryGetFixDataAsync( } var textChanges = await GetTextChangesAsync( - document, node, allowInHiddenRegions, hasExistingImport, cancellationToken).ConfigureAwait(false); + document, node, options, hasExistingImport, cancellationToken).ConfigureAwait(false); return GetFixData( document, textChanges, description, @@ -128,7 +127,7 @@ protected abstract AddImportFixData GetFixData( protected abstract CodeActionPriority GetPriority(Document document); protected virtual (string description, bool hasExistingImport) GetDescription( - Document document, OptionSet options, SyntaxNode node, + Document document, AddImportPlacementOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { return provider.GetDescription( diff --git a/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs b/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs index 58e4d3b03b9af..a40efe709a4d8 100644 --- a/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs +++ b/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs @@ -25,9 +25,10 @@ internal interface ICallback ValueTask> GetFixesAsync( PinnedSolutionInfo solutionInfo, RemoteServiceCallbackId callbackId, DocumentId documentId, TextSpan span, string diagnosticId, int maxResults, - bool allowInHiddenRegions, bool searchReferenceAssemblies, ImmutableArray packageSources, CancellationToken cancellationToken); + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); + ValueTask> GetUniqueFixesAsync( PinnedSolutionInfo solutionInfo, RemoteServiceCallbackId callbackId, DocumentId id, TextSpan span, ImmutableArray diagnosticIds, - bool searchReferenceAssemblies, ImmutableArray packageSources, CancellationToken cancellationToken); + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs index e5ef181bb091e..6514dc0f4cb92 100644 --- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs +++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs @@ -39,15 +39,17 @@ private partial class SymbolReferenceFinder private readonly SyntaxNode _node; private readonly ISymbolSearchService _symbolSearchService; - private readonly bool _searchReferenceAssemblies; + private readonly AddImportOptions _options; private readonly ImmutableArray _packageSources; public SymbolReferenceFinder( AbstractAddImportFeatureService owner, - Document document, SemanticModel semanticModel, - string diagnosticId, SyntaxNode node, + Document document, + SemanticModel semanticModel, + string diagnosticId, + SyntaxNode node, ISymbolSearchService symbolSearchService, - bool searchReferenceAssemblies, + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { @@ -58,14 +60,8 @@ public SymbolReferenceFinder( _node = node; _symbolSearchService = symbolSearchService; - _searchReferenceAssemblies = searchReferenceAssemblies; + _options = options; _packageSources = packageSources; - - if (_searchReferenceAssemblies || packageSources.Length > 0) - { - Contract.ThrowIfNull(symbolSearchService); - } - _syntaxFacts = document.GetLanguageService(); _namespacesInScope = GetNamespacesInScope(cancellationToken); @@ -217,14 +213,13 @@ private async Task> GetReferencesForMatchingType var typeSymbols = OfType(symbols); - var hideAdvancedMembers = _document.Project.Solution.Options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, _document.Project.Language); var editorBrowserInfo = new EditorBrowsableInfo(_semanticModel.Compilation); // Only keep symbols which are accessible from the current location and that are allowed by the current // editor browsable rules. var accessibleTypeSymbols = typeSymbols.WhereAsArray( s => ArityAccessibilityAndAttributeContextAreCorrect(s.Symbol, arity, inAttributeContext, hasIncompleteParentMember, looksGeneric) && - s.Symbol.IsEditorBrowsable(hideAdvancedMembers, _semanticModel.Compilation, editorBrowserInfo)); + s.Symbol.IsEditorBrowsable(_options.HideAdvancedMembers, _semanticModel.Compilation, editorBrowserInfo)); // These types may be contained within namespaces, or they may be nested // inside generic types. Record these namespaces/types if it would be diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs index 293fafcd0faaa..af318c6558c01 100644 --- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs +++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs @@ -66,7 +66,7 @@ private async Task FindNugetOrReferenceAssemblyTypeReferencesWorkerAsync( ArrayBuilder allReferences, TSimpleNameSyntax nameNode, string name, int arity, bool isAttributeSearch, CancellationToken cancellationToken) { - if (_searchReferenceAssemblies) + if (_options.SearchOptions.SearchReferenceAssemblies) { cancellationToken.ThrowIfCancellationRequested(); await FindReferenceAssemblyTypeReferencesAsync( diff --git a/src/Features/Core/Portable/AddObsoleteAttribute/AbstractAddObsoleteAttributeCodeFixProvider.cs b/src/Features/Core/Portable/AddObsoleteAttribute/AbstractAddObsoleteAttributeCodeFixProvider.cs index 8e2a19f2356f8..3d8a78d4c50c4 100644 --- a/src/Features/Core/Portable/AddObsoleteAttribute/AbstractAddObsoleteAttributeCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddObsoleteAttribute/AbstractAddObsoleteAttributeCodeFixProvider.cs @@ -80,6 +80,10 @@ protected override async Task FixAllAsync( SyntaxEditor editor, CancellationToken cancellationToken) { var obsoleteAttribute = await GetObsoleteAttributeAsync(document, cancellationToken).ConfigureAwait(false); + + // RegisterCodeFixesAsync checked for null + Contract.ThrowIfNull(obsoleteAttribute); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var containers = diagnostics.Select(d => GetContainer(root, d.Location.FindNode(cancellationToken))) diff --git a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs index 32a75063ea2ac..376f536c68e23 100644 --- a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs @@ -49,16 +49,10 @@ protected async Task> GetAddPackagesCodeActionsAsync( var symbolSearchService = _symbolSearchService ?? workspaceServices.GetService(); var installerService = _packageInstallerService ?? workspaceServices.GetService(); - var language = document.Project.Language; - - var options = document.Project.Solution.Options; - var searchNugetPackages = options.GetOption( - SymbolSearchOptions.SuggestForTypesInNuGetPackages, language); - var codeActions = ArrayBuilder.GetInstance(); if (symbolSearchService != null && installerService != null && - searchNugetPackages && + context.Options.SearchOptions.SearchNuGetPackages && installerService.IsEnabled(document.Project.Id)) { var packageSources = PackageSourceHelper.GetPackageSources(installerService.TryGetPackageSources()); diff --git a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs index c60aacf029644..7cd5fb2b89dfe 100644 --- a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs @@ -278,18 +278,19 @@ ImmutableArray NestByCascading() { using var builderDisposer = ArrayBuilder.GetInstance(capacity: 2, out var builder); - var nonCascadingActions = ImmutableArray.CreateRange(codeFixData, data => + var nonCascadingActions = codeFixData.SelectAsArray(data => { var title = GetCodeFixTitle(FeaturesResources.Add_to_0, data.Method, includeParameters: true); - return new MyCodeAction(title: title, data.CreateChangedSolutionNonCascading); + return (CodeAction)new MyCodeAction(title: title, data.CreateChangedSolutionNonCascading); }); - var cascading = codeFixData.Where(data => data.CreateChangedSolutionCascading != null); - var cascadingActions = ImmutableArray.CreateRange(cascading.Select(data => - { - var title = GetCodeFixTitle(FeaturesResources.Add_to_0, data.Method, includeParameters: true); - return new MyCodeAction(title: title, data.CreateChangedSolutionCascading); - })); + var cascadingActions = codeFixData.SelectAsArray( + data => data.CreateChangedSolutionCascading != null, + data => + { + var title = GetCodeFixTitle(FeaturesResources.Add_to_0, data.Method, includeParameters: true); + return (CodeAction)new MyCodeAction(title: title, data.CreateChangedSolutionCascading!); + }); var aMethod = codeFixData.First().Method; // We need to term the MethodGroup and need an arbitrary IMethodSymbol to do so. var nestedNonCascadingTitle = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, aMethod, includeParameters: false); @@ -325,7 +326,7 @@ private static ImmutableArray PrepareCreationOfCodeActions( var methodToUpdate = argumentInsertPositionData.MethodToUpdate; var argumentToInsert = argumentInsertPositionData.ArgumentToInsert; - var cascadingFix = AddParameterService.Instance.HasCascadingDeclarations(methodToUpdate) + var cascadingFix = AddParameterService.HasCascadingDeclarations(methodToUpdate) ? new Func>(c => FixAsync(document, methodToUpdate, argumentToInsert, arguments, fixAllReferences: true, c)) : null; @@ -372,7 +373,7 @@ private static async Task FixAsync( invocationDocument, argument, cancellationToken).ConfigureAwait(false); var newParameterIndex = isNamedArgument ? (int?)null : argumentList.IndexOf(argument); - return await AddParameterService.Instance.AddParameterAsync( + return await AddParameterService.AddParameterAsync( invocationDocument, method, argumentType, diff --git a/src/Features/Core/Portable/AddParameter/AddParameterService.cs b/src/Features/Core/Portable/AddParameter/AddParameterService.cs index 017505dd01965..e08c51bed9546 100644 --- a/src/Features/Core/Portable/AddParameter/AddParameterService.cs +++ b/src/Features/Core/Portable/AddParameter/AddParameterService.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -13,21 +12,18 @@ using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; namespace Microsoft.CodeAnalysis.AddParameter { - internal class AddParameterService : IAddParameterService + internal static class AddParameterService { - private AddParameterService() - { - } - - public static AddParameterService Instance = new(); - - public bool HasCascadingDeclarations(IMethodSymbol method) + /// + /// Checks if there are indications that there might be more than one declarations that need to be fixed. + /// The check does not look-up if there are other declarations (this is done later in the CodeAction). + /// + public static bool HasCascadingDeclarations(IMethodSymbol method) { // Don't cascade constructors if (method.IsConstructor()) @@ -69,10 +65,15 @@ public bool HasCascadingDeclarations(IMethodSymbol method) return false; } - public async Task AddParameterAsync( + /// + /// Adds a parameter to a method. + /// + /// to add as the final parameter + /// + public static async Task AddParameterAsync( Document invocationDocument, IMethodSymbol method, - ITypeSymbol newParamaterType, + ITypeSymbol newParameterType, RefKind refKind, string parameterName, int? newParameterIndex, @@ -98,7 +99,7 @@ public 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); + var editor = new SyntaxEditor(syntaxRoot, solution.Workspace.Services); var generator = editor.Generator; foreach (var methodDeclaration in documentLookup) { @@ -112,9 +113,9 @@ public async Task AddParameterAsync( syntaxFacts.GetDefaultOfParameter(existingParameters[insertionIndex - 1]) != null; var parameterSymbol = CreateParameterSymbol( - methodDeclaration, newParamaterType, refKind, parameterMustBeOptional, parameterName); + methodDeclaration, newParameterType, refKind, parameterMustBeOptional, parameterName); - var argumentInitializer = parameterMustBeOptional ? generator.DefaultExpression(newParamaterType) : null; + var argumentInitializer = parameterMustBeOptional ? generator.DefaultExpression(newParameterType) : null; var parameterDeclaration = generator.ParameterDeclaration(parameterSymbol, argumentInitializer) .WithAdditionalAnnotations(Formatter.Annotation); if (anySymbolReferencesNotInSource && methodDeclaration == method) @@ -128,7 +129,7 @@ public async Task AddParameterAsync( insertionIndex++; } - AddParameter(syntaxFacts, editor, methodNode, insertionIndex, parameterDeclaration, cancellationToken); + AddParameterEditor.AddParameter(syntaxFacts, editor, methodNode, insertionIndex, parameterDeclaration, cancellationToken); } var newRoot = editor.GetChangedRoot(); @@ -165,163 +166,5 @@ private static IParameterSymbol CreateParameterSymbol( attributes: default, refKind: refKind, isOptional: isOptional, isParams: false, type: parameterType, name: uniqueName); return newParameterSymbol; } - - private static void AddParameter( - ISyntaxFactsService syntaxFacts, - SyntaxEditor editor, - SyntaxNode declaration, - int insertionIndex, - SyntaxNode parameterDeclaration, - CancellationToken cancellationToken) - { - var sourceText = declaration.SyntaxTree.GetText(cancellationToken); - var generator = editor.Generator; - - var existingParameters = generator.GetParameters(declaration); - var placeOnNewLine = ShouldPlaceParametersOnNewLine(existingParameters, cancellationToken); - - if (!placeOnNewLine) - { - // Trivial case. Just let the stock editor impl handle this for us. - editor.InsertParameter(declaration, insertionIndex, parameterDeclaration); - return; - } - - if (insertionIndex == existingParameters.Count) - { - // Placing the last parameter on its own line. Get the indentation of the - // curent last parameter and give the new last parameter the same indentation. - var leadingIndentation = GetDesiredLeadingIndentation( - generator, syntaxFacts, existingParameters[existingParameters.Count - 1], includeLeadingNewLine: true); - parameterDeclaration = parameterDeclaration.WithPrependedLeadingTrivia(leadingIndentation) - .WithAdditionalAnnotations(Formatter.Annotation); - - editor.AddParameter(declaration, parameterDeclaration); - } - else if (insertionIndex == 0) - { - // Inserting into the start of the list. The existing first parameter might - // be on the same line as the parameter list, or it might be on the next line. - var firstParameter = existingParameters[0]; - var previousToken = firstParameter.GetFirstToken().GetPreviousToken(); - - if (sourceText.AreOnSameLine(previousToken, firstParameter.GetFirstToken())) - { - // First parameter is on hte same line as the method. - - // We want to insert the parameter at the front of the existing parameter - // list. That means we need to move the current first parameter to a new - // line. Give the current first parameter the indentation of the second - // parameter in the list. - editor.InsertParameter(declaration, insertionIndex, parameterDeclaration); - var nextParameter = existingParameters[insertionIndex]; - - var nextLeadingIndentation = GetDesiredLeadingIndentation( - generator, syntaxFacts, existingParameters[insertionIndex + 1], includeLeadingNewLine: true); - editor.ReplaceNode( - nextParameter, - nextParameter.WithPrependedLeadingTrivia(nextLeadingIndentation) - .WithAdditionalAnnotations(Formatter.Annotation)); - } - else - { - // First parameter is on its own line. No need to adjust its indentation. - // Just copy its indentation over to the parameter we're inserting, and - // make sure the current first parameter gets a newline so it stays on - // its own line. - - // We want to insert the parameter at the front of the existing parameter - // list. That means we need to move the current first parameter to a new - // line. Give the current first parameter the indentation of the second - // parameter in the list. - var firstLeadingIndentation = GetDesiredLeadingIndentation( - generator, syntaxFacts, existingParameters[0], includeLeadingNewLine: false); - - editor.InsertParameter(declaration, insertionIndex, - parameterDeclaration.WithLeadingTrivia(firstLeadingIndentation)); - var nextParameter = existingParameters[insertionIndex]; - - editor.ReplaceNode( - nextParameter, - nextParameter.WithPrependedLeadingTrivia(generator.ElasticCarriageReturnLineFeed) - .WithAdditionalAnnotations(Formatter.Annotation)); - } - } - else - { - // We're inserting somewhere after the start (but not at the end). Because - // we've set placeOnNewLine, we know that the current comma we'll be placed - // after already have a newline following it. So all we need for this new - // parameter is to get the indentation of the following parameter. - // Because we're going to 'steal' the existing comma from that parameter, - // ensure that the next parameter has a new-line added to it so that it will - // still stay on a new line. - var nextParameter = existingParameters[insertionIndex]; - var leadingIndentation = GetDesiredLeadingIndentation( - generator, syntaxFacts, existingParameters[insertionIndex], includeLeadingNewLine: false); - parameterDeclaration = parameterDeclaration.WithPrependedLeadingTrivia(leadingIndentation); - - editor.InsertParameter(declaration, insertionIndex, parameterDeclaration); - editor.ReplaceNode( - nextParameter, - nextParameter.WithPrependedLeadingTrivia(generator.ElasticCarriageReturnLineFeed) - .WithAdditionalAnnotations(Formatter.Annotation)); - } - } - - private static ImmutableArray GetDesiredLeadingIndentation( - SyntaxGenerator generator, ISyntaxFactsService syntaxFacts, - SyntaxNode node, bool includeLeadingNewLine) - { - using var _ = ArrayBuilder.GetInstance(out var triviaList); - if (includeLeadingNewLine) - { - triviaList.Add(generator.ElasticCarriageReturnLineFeed); - } - - var lastWhitespace = default(SyntaxTrivia); - foreach (var trivia in node.GetLeadingTrivia().Reverse()) - { - if (syntaxFacts.IsWhitespaceTrivia(trivia)) - { - lastWhitespace = trivia; - } - else if (syntaxFacts.IsEndOfLineTrivia(trivia)) - { - break; - } - } - - if (lastWhitespace.RawKind != 0) - { - triviaList.Add(lastWhitespace); - } - - return triviaList.ToImmutable(); - } - - private static bool ShouldPlaceParametersOnNewLine( - IReadOnlyList parameters, CancellationToken cancellationToken) - { - if (parameters.Count <= 1) - { - return false; - } - - var text = parameters[0].SyntaxTree.GetText(cancellationToken); - for (int i = 1, n = parameters.Count; i < n; i++) - { - var lastParameter = parameters[i - 1]; - var thisParameter = parameters[i]; - - if (text.AreOnSameLine(lastParameter.GetLastToken(), thisParameter.GetFirstToken())) - { - return false; - } - } - - // All parameters are on different lines. Place the new parameter on a new line as well. - return true; - } } } diff --git a/src/Features/Core/Portable/AddParameter/CodeFixData.cs b/src/Features/Core/Portable/AddParameter/CodeFixData.cs index 5a7d7fa47a22a..9fac17be00b35 100644 --- a/src/Features/Core/Portable/AddParameter/CodeFixData.cs +++ b/src/Features/Core/Portable/AddParameter/CodeFixData.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Threading; using System.Threading.Tasks; @@ -15,7 +13,7 @@ internal readonly struct CodeFixData public CodeFixData( IMethodSymbol method, Func> createChangedSolutionNonCascading, - Func> createChangedSolutionCascading) + Func>? createChangedSolutionCascading) { Method = method ?? throw new ArgumentNullException(nameof(method)); CreateChangedSolutionNonCascading = createChangedSolutionNonCascading ?? throw new ArgumentNullException(nameof(createChangedSolutionNonCascading)); @@ -35,6 +33,6 @@ public CodeFixData( /// /// An optional fix for the overload with cascading. /// - public Func> CreateChangedSolutionCascading { get; } + public Func>? CreateChangedSolutionCascading { get; } } } diff --git a/src/Features/Core/Portable/AddParameter/IAddParameterService.cs b/src/Features/Core/Portable/AddParameter/IAddParameterService.cs deleted file mode 100644 index 6c5839bdea0cb..0000000000000 --- a/src/Features/Core/Portable/AddParameter/IAddParameterService.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.Threading; -using System.Threading.Tasks; - -namespace Microsoft.CodeAnalysis.AddParameter -{ - internal interface IAddParameterService - { - /// - /// Checks if there are indications that there might be more than one declarations that need to be fixed. - /// The check does not look-up if there are other declarations (this is done later in the CodeAction). - /// - bool HasCascadingDeclarations(IMethodSymbol method); - - /// - /// Adds a parameter to a method. - /// - /// to add as the final parameter - /// - Task AddParameterAsync( - Document invocationDocument, - IMethodSymbol method, - ITypeSymbol newParamaterType, - RefKind refKind, - string parameterName, - int? newParameterIndex, - bool fixAllReferences, - CancellationToken cancellationToken); - } -} diff --git a/src/Features/Core/Portable/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs b/src/Features/Core/Portable/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs index bd12d7f4e6f0f..ece6c991a3617 100644 --- a/src/Features/Core/Portable/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs +++ b/src/Features/Core/Portable/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs @@ -7,9 +7,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -43,9 +44,10 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var addImportService = document.GetRequiredLanguageService(); var syntaxGenerator = document.GetRequiredLanguageService(); + var codeGenerator = document.GetRequiredLanguageService(); var compilation = semanticModel.Compilation; - var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var allowInHiddenRegions = document.CanAddImportsInHiddenRegions(); + var options = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var codeActionsBuilder = ImmutableArray.CreateBuilder(symbolInfo.CandidateSymbols.Length); foreach (var symbol in symbolInfo.CandidateSymbols.Cast()) { @@ -54,7 +56,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) codeActionsBuilder.Add(new MyCodeAction(codeActionPreviewText, c => { var aliasDirective = syntaxGenerator.AliasImportDeclaration(typeName, symbol); - var newRoot = addImportService.AddImport(compilation, root, diagnosticNode, aliasDirective, syntaxGenerator, optionSet, allowInHiddenRegions, cancellationToken); + var newRoot = addImportService.AddImport(compilation, root, diagnosticNode, aliasDirective, syntaxGenerator, options, cancellationToken); return Task.FromResult(document.WithSyntaxRoot(newRoot)); })); } diff --git a/src/Features/Core/Portable/BraceCompletion/AbstractBraceCompletionService.cs b/src/Features/Core/Portable/BraceCompletion/AbstractBraceCompletionService.cs index 09111582b3e4b..29526a6201f06 100644 --- a/src/Features/Core/Portable/BraceCompletion/AbstractBraceCompletionService.cs +++ b/src/Features/Core/Portable/BraceCompletion/AbstractBraceCompletionService.cs @@ -5,8 +5,8 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -63,10 +63,10 @@ internal abstract class AbstractBraceCompletionService : IBraceCompletionService return new BraceCompletionResult(ImmutableArray.Create(braceTextEdit), caretLocation); } - public virtual Task GetTextChangesAfterCompletionAsync(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken) + public virtual Task GetTextChangesAfterCompletionAsync(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken) => SpecializedTasks.Default(); - public virtual Task GetTextChangeAfterReturnAsync(BraceCompletionContext braceCompletionContext, DocumentOptionSet documentOptions, CancellationToken cancellationToken) + public virtual Task GetTextChangeAfterReturnAsync(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken) => SpecializedTasks.Default(); public virtual async Task CanProvideBraceCompletionAsync(char brace, int openingPosition, Document document, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/BraceCompletion/BraceCompletionOptions.cs b/src/Features/Core/Portable/BraceCompletion/BraceCompletionOptions.cs deleted file mode 100644 index 15801380d8d2b..0000000000000 --- a/src/Features/Core/Portable/BraceCompletion/BraceCompletionOptions.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.BraceCompletion -{ - internal class BraceCompletionOptions - { - public static readonly PerLanguageOption2 AutoFormattingOnCloseBrace = new( - nameof(BraceCompletionOptions), nameof(AutoFormattingOnCloseBrace), defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Close Brace")); - - [ExportSolutionOptionProvider, Shared] - internal class BraceCompletionOptionsProvider : IOptionProvider - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public BraceCompletionOptionsProvider() - { - } - - public ImmutableArray Options { get; } = ImmutableArray.Create( - AutoFormattingOnCloseBrace); - } - } -} diff --git a/src/Features/Core/Portable/BraceCompletion/IBraceCompletionService.cs b/src/Features/Core/Portable/BraceCompletion/IBraceCompletionService.cs index 008fd586cf58a..0da69a7acabd7 100644 --- a/src/Features/Core/Portable/BraceCompletion/IBraceCompletionService.cs +++ b/src/Features/Core/Portable/BraceCompletion/IBraceCompletionService.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Indentation; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; @@ -45,12 +46,12 @@ internal interface IBraceCompletionService : ILanguageService /// 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, CancellationToken cancellationToken); + Task GetTextChangesAfterCompletionAsync(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, DocumentOptionSet documentOptions, CancellationToken cancellationToken); + Task GetTextChangeAfterReturnAsync(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken); /// /// Returns the brace completion context if the caret is located between an already completed diff --git a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs index b27637de58c64..79a9778e0f8c9 100644 --- a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs +++ b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; @@ -398,12 +399,13 @@ private static async Task> FindChangeSignatureR }); var annotatedNodes = newRoot.GetAnnotatedNodes(syntaxAnnotation: changeSignatureFormattingAnnotation); + var formattingOptions = await SyntaxFormattingOptions.FromDocumentAsync(doc, cancellationToken).ConfigureAwait(false); var formattedRoot = Formatter.Format( newRoot, changeSignatureFormattingAnnotation, - doc.Project.Solution.Workspace, - options: await doc.GetOptionsAsync(cancellationToken).ConfigureAwait(false), + doc.Project.Solution.Workspace.Services, + options: formattingOptions, rules: GetFormattingRules(doc), cancellationToken: CancellationToken.None); @@ -414,7 +416,8 @@ private static async Task> FindChangeSignatureR foreach (var docId in nodesToUpdate.Keys) { var updatedDoc = currentSolution.GetRequiredDocument(docId).WithSyntaxRoot(updatedRoots[docId]); - var docWithImports = await ImportAdder.AddImportsFromSymbolAnnotationAsync(updatedDoc, cancellationToken: cancellationToken).ConfigureAwait(false); + var addImportOptions = await AddImportPlacementOptions.FromDocumentAsync(updatedDoc, cancellationToken).ConfigureAwait(false); + var docWithImports = await ImportAdder.AddImportsFromSymbolAnnotationAsync(updatedDoc, addImportOptions, cancellationToken).ConfigureAwait(false); var reducedDoc = await Simplifier.ReduceAsync(docWithImports, Simplifier.Annotation, cancellationToken: cancellationToken).ConfigureAwait(false); var formattedDoc = await Formatter.FormatAsync(reducedDoc, SyntaxAnnotation.ElasticAnnotation, cancellationToken: cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/CodeCleanup/AbstractCodeCleanupService.cs b/src/Features/Core/Portable/CodeCleanup/AbstractCodeCleanupService.cs index 4856d21bda509..42ee1c96c1251 100644 --- a/src/Features/Core/Portable/CodeCleanup/AbstractCodeCleanupService.cs +++ b/src/Features/Core/Portable/CodeCleanup/AbstractCodeCleanupService.cs @@ -5,13 +5,13 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeCleanup { @@ -31,6 +31,7 @@ public async Task CleanupAsync( Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, + CodeActionOptions options, CancellationToken cancellationToken) { // add one item for the 'format' action we'll do last @@ -48,7 +49,7 @@ public async Task CleanupAsync( } document = await ApplyCodeFixesAsync( - document, enabledDiagnostics.Diagnostics, progressTracker, cancellationToken).ConfigureAwait(false); + document, enabledDiagnostics.Diagnostics, progressTracker, options, cancellationToken).ConfigureAwait(false); // do the remove usings after code fix, as code fix might remove some code which can results in unused usings. if (organizeUsings) @@ -100,7 +101,7 @@ private static async Task RemoveSortUsingsAsync( private async Task ApplyCodeFixesAsync( Document document, ImmutableArray enabledDiagnosticSets, - IProgressTracker progressTracker, CancellationToken cancellationToken) + IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken) { // Add a progress item for each enabled option we're going to fixup. progressTracker.AddItems(enabledDiagnosticSets.Length); @@ -111,7 +112,7 @@ private async Task ApplyCodeFixesAsync( progressTracker.Description = diagnosticSet.Description; document = await ApplyCodeFixesForSpecificDiagnosticIdsAsync( - document, diagnosticSet.DiagnosticIds, progressTracker, cancellationToken).ConfigureAwait(false); + document, diagnosticSet.DiagnosticIds, progressTracker, options, cancellationToken).ConfigureAwait(false); // Mark this option as being completed. progressTracker.ItemCompleted(); @@ -121,14 +122,14 @@ private async Task ApplyCodeFixesAsync( } private async Task ApplyCodeFixesForSpecificDiagnosticIdsAsync( - Document document, ImmutableArray diagnosticIds, IProgressTracker progressTracker, CancellationToken cancellationToken) + Document document, ImmutableArray diagnosticIds, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken) { foreach (var diagnosticId in diagnosticIds) { using (Logger.LogBlock(FunctionId.CodeCleanup_ApplyCodeFixesAsync, diagnosticId, cancellationToken)) { document = await _codeFixService.ApplyCodeFixesForSpecificDiagnosticIdAsync( - document, diagnosticId, progressTracker, cancellationToken).ConfigureAwait(false); + document, diagnosticId, progressTracker, options, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/CodeCleanup/ICodeCleanupService.cs b/src/Features/Core/Portable/CodeCleanup/ICodeCleanupService.cs index e4fe64bab3dbb..5a59c9196d52c 100644 --- a/src/Features/Core/Portable/CodeCleanup/ICodeCleanupService.cs +++ b/src/Features/Core/Portable/CodeCleanup/ICodeCleanupService.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -11,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CodeCleanup { internal interface ICodeCleanupService : ILanguageService { - Task CleanupAsync(Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, CancellationToken cancellationToken); + Task CleanupAsync(Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken); EnabledDiagnosticOptions GetAllDiagnostics(); } } diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs index a33099b6eb8bf..c28c4dcc1c907 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs @@ -157,7 +157,7 @@ public async Task> GetFixesAsync( Document document, TextSpan range, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken) { @@ -219,7 +219,7 @@ public async Task> GetFixesAsync( { await AppendFixesAsync( document, spanAndDiagnostic.Key, spanAndDiagnostic.Value, fixAllForInSpan: false, - priority, isBlocking, result, addOperationScope, cancellationToken).ConfigureAwait(false); + priority, options, result, addOperationScope, cancellationToken).ConfigureAwait(false); } } @@ -266,7 +266,7 @@ Func GetFixableDiagnosticFilter(Document document) } } - public async Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan range, string diagnosticId, CancellationToken cancellationToken) + public async Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan range, string diagnosticId, CodeActionOptions options, CancellationToken cancellationToken) { var diagnostics = (await _diagnosticService.GetDiagnosticsForSpanAsync(document, range, diagnosticId, includeSuppressedDiagnostics: false, cancellationToken: cancellationToken).ConfigureAwait(false)).ToList(); if (diagnostics.Count == 0) @@ -275,20 +275,20 @@ Func GetFixableDiagnosticFilter(Document document) } using var resultDisposer = ArrayBuilder.GetInstance(out var result); - await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, CodeActionRequestPriority.None, isBlocking: false, result, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, CodeActionRequestPriority.None, options, result, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); // TODO: Just get the first fix for now until we have a way to config user's preferred fix // https://github.com/dotnet/roslyn/issues/27066 return result.ToImmutable().FirstOrDefault(); } - public async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CancellationToken cancellationToken) + public async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken) { var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var textSpan = new TextSpan(0, tree.Length); var fixCollection = await GetDocumentFixAllForIdInSpanAsync( - document, textSpan, diagnosticId, cancellationToken).ConfigureAwait(false); + document, textSpan, diagnosticId, options, cancellationToken).ConfigureAwait(false); if (fixCollection == null) { return document; @@ -372,7 +372,7 @@ private async Task AppendFixesAsync( IEnumerable diagnostics, bool fixAllForInSpan, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, ArrayBuilder result, Func addOperationScope, CancellationToken cancellationToken) @@ -453,13 +453,13 @@ await AppendFixesOrConfigurationsAsync( if (fixAllForInSpan) { var primaryDiagnostic = dxs.First(); - return GetCodeFixesAsync(document, primaryDiagnostic.Location.SourceSpan, fixer, fixerMetadata, isBlocking, + return GetCodeFixesAsync(document, primaryDiagnostic.Location.SourceSpan, fixer, fixerMetadata, options, ImmutableArray.Create(primaryDiagnostic), uniqueDiagosticToEquivalenceKeysMap, diagnosticAndEquivalenceKeyToFixersMap, cancellationToken); } else { - return GetCodeFixesAsync(document, span, fixer, fixerMetadata, isBlocking, dxs, + return GetCodeFixesAsync(document, span, fixer, fixerMetadata, options, dxs, uniqueDiagosticToEquivalenceKeysMap, diagnosticAndEquivalenceKeyToFixersMap, cancellationToken); } } @@ -481,7 +481,7 @@ await AppendFixesOrConfigurationsAsync( } private static async Task> GetCodeFixesAsync( - Document document, TextSpan span, CodeFixProvider fixer, CodeChangeProviderMetadata? fixerMetadata, bool isBlocking, + Document document, TextSpan span, CodeFixProvider fixer, CodeChangeProviderMetadata? fixerMetadata, CodeActionOptions options, ImmutableArray diagnostics, Dictionary> uniqueDiagosticToEquivalenceKeysMap, Dictionary<(Diagnostic diagnostic, string? equivalenceKey), CodeFixProvider> diagnosticAndEquivalenceKeyToFixersMap, @@ -510,7 +510,7 @@ private static async Task> GetCodeFixesAsync( } } }, - isBlocking, + options, cancellationToken); var task = fixer.RegisterCodeFixesAsync(context) ?? Task.CompletedTask; diff --git a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs index 107c26f8d0467..4d56475ff006d 100644 --- a/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs +++ b/src/Features/Core/Portable/CodeFixes/Configuration/ConfigurationUpdater.cs @@ -474,6 +474,7 @@ internal static bool TryGetEditorConfigStringParts( TextLine? lastValidSpecificHeaderSpanEnd = null; var textChange = new TextChange(); + var isGlobalConfig = false; foreach (var curLine in result.Lines) { @@ -494,6 +495,20 @@ internal static bool TryGetEditorConfigStringParts( var severitySuffixInValue = groups[3].Value.ToString(); var commentValue = groups[4].Value.ToString(); + // Check for global config header: "is_global = true" + if (mostRecentHeader == null && + lastValidHeader == null && + key.Equals("is_global", StringComparison.OrdinalIgnoreCase) && + value.Trim().Equals("true", StringComparison.OrdinalIgnoreCase) && + severitySuffixInValue.Length == 0) + { + isGlobalConfig = true; + mostRecentHeader = curLine; + lastValidHeader = curLine; + lastValidHeaderSpanEnd = curLine; + continue; + } + // Verify the most recent header is a valid header if (mostRecentHeader != null && lastValidHeader != null && @@ -573,7 +588,7 @@ internal static bool TryGetEditorConfigStringParts( } } } - else if (s_headerPattern.IsMatch(curLineText.Trim())) + else if (!isGlobalConfig && s_headerPattern.IsMatch(curLineText.Trim())) { // We found a header entry such as '[*.cs]', '[*.vb]', etc. // Verify that header is valid. diff --git a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs index ffa0dcb75aebb..c001b53f37052 100644 --- a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs @@ -15,19 +15,16 @@ namespace Microsoft.CodeAnalysis.CodeFixes { internal interface ICodeFixService { - Task> GetFixesAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); - Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan textSpan, string diagnosticId, CancellationToken cancellationToken); - Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CancellationToken cancellationToken); + Task> GetFixesAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken); + Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan textSpan, string diagnosticId, CodeActionOptions options, CancellationToken cancellationToken); + Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken); CodeFixProvider? GetSuppressionFixer(string language, IEnumerable diagnosticIds); Task GetMostSevereFixableDiagnosticAsync(Document document, TextSpan range, CancellationToken cancellationToken); } internal static class ICodeFixServiceExtensions { - public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, CancellationToken cancellationToken) - => service.GetFixesAsync(document, range, isBlocking: false, cancellationToken); - - public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, bool isBlocking, CancellationToken cancellationToken) - => service.GetFixesAsync(document, range, CodeActionRequestPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); + public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, CodeActionOptions options, CancellationToken cancellationToken) + => service.GetFixesAsync(document, range, CodeActionRequestPriority.None, options, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs index 8a39bb7fd11b5..8f726c066a145 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs @@ -6,7 +6,8 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression @@ -33,13 +34,13 @@ public GlobalSuppressMessageCodeAction( protected override async Task GetChangedSuppressionDocumentAsync(CancellationToken cancellationToken) { var suppressionsDoc = await GetOrCreateSuppressionsDocumentAsync(cancellationToken).ConfigureAwait(false); - var workspace = suppressionsDoc.Project.Solution.Workspace; + var services = suppressionsDoc.Project.Solution.Workspace.Services; var suppressionsRoot = await suppressionsDoc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var compilation = await suppressionsDoc.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var addImportsService = suppressionsDoc.GetRequiredLanguageService(); + var options = await SyntaxFormattingOptions.FromDocumentAsync(suppressionsDoc, cancellationToken).ConfigureAwait(false); suppressionsRoot = Fixer.AddGlobalSuppressMessageAttribute( - suppressionsRoot, _targetSymbol, _suppressMessageAttribute, _diagnostic, workspace, compilation, addImportsService, cancellationToken); + suppressionsRoot, _targetSymbol, _suppressMessageAttribute, _diagnostic, services, options, addImportsService, cancellationToken); return suppressionsDoc.WithSyntaxRoot(suppressionsRoot); } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs index b6a23d39b77e7..407042a49b2dd 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs @@ -11,10 +11,11 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Formatting; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression @@ -120,10 +121,10 @@ private static async Task CreateChangedSolutionAsync(AbstractSuppressi protected override async Task GetChangedSuppressionDocumentAsync(CancellationToken cancellationToken) { var suppressionsDoc = await GetOrCreateSuppressionsDocumentAsync(cancellationToken).ConfigureAwait(false); - var workspace = suppressionsDoc.Project.Solution.Workspace; + var services = suppressionsDoc.Project.Solution.Workspace.Services; var suppressionsRoot = await suppressionsDoc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var compilation = await suppressionsDoc.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var addImportsService = suppressionsDoc.GetRequiredLanguageService(); + var options = await SyntaxFormattingOptions.FromDocumentAsync(suppressionsDoc, cancellationToken).ConfigureAwait(false); foreach (var (targetSymbol, diagnostics) in _diagnosticsBySymbol) { @@ -132,7 +133,7 @@ protected override async Task GetChangedSuppressionDocumentAsync(Cance Contract.ThrowIfFalse(!diagnostic.IsSuppressed); suppressionsRoot = Fixer.AddGlobalSuppressMessageAttribute( suppressionsRoot, targetSymbol, _suppressMessageAttribute, diagnostic, - workspace, compilation, addImportsService, cancellationToken); + services, options, addImportsService, cancellationToken); } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs index 5a1bf7eed6ac2..20e102c4bfaab 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs @@ -104,8 +104,9 @@ internal static SyntaxToken GetNewStartTokenWithAddedPragma( TextSpan currentDiagnosticSpan, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, - Func formatNode, - bool isRemoveSuppression = false) + Func formatNode, + bool isRemoveSuppression, + CancellationToken cancellationToken) { var trivia = startToken.LeadingTrivia.ToImmutableArray(); var index = GetPositionForPragmaInsertion(trivia, currentDiagnosticSpan, fixer, isStartToken: true, triviaAtIndex: out var insertAfterTrivia); @@ -126,8 +127,8 @@ internal static SyntaxToken GetNewStartTokenWithAddedPragma( } var pragmaTrivia = !isRemoveSuppression - ? fixer.CreatePragmaDisableDirectiveTrivia(diagnostic, formatNode, needsLeadingEOL, needsTrailingEndOfLine: true) - : fixer.CreatePragmaRestoreDirectiveTrivia(diagnostic, formatNode, needsLeadingEOL, needsTrailingEndOfLine: true); + ? fixer.CreatePragmaDisableDirectiveTrivia(diagnostic, formatNode, needsLeadingEOL, needsTrailingEndOfLine: true, cancellationToken) + : fixer.CreatePragmaRestoreDirectiveTrivia(diagnostic, formatNode, needsLeadingEOL, needsTrailingEndOfLine: true, cancellationToken); return startToken.WithLeadingTrivia(trivia.InsertRange(index, pragmaTrivia)); } @@ -155,8 +156,9 @@ internal static SyntaxToken GetNewEndTokenWithAddedPragma( TextSpan currentDiagnosticSpan, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, - Func formatNode, - bool isRemoveSuppression = false) + Func formatNode, + bool isRemoveSuppression, + CancellationToken cancellationToken) { ImmutableArray trivia; var isEOF = fixer.IsEndOfFileToken(endToken); @@ -186,8 +188,8 @@ internal static SyntaxToken GetNewEndTokenWithAddedPragma( } var pragmaTrivia = !isRemoveSuppression - ? fixer.CreatePragmaRestoreDirectiveTrivia(diagnostic, formatNode, needsLeadingEndOfLine: true, needsTrailingEndOfLine: needsTrailingEOL) - : fixer.CreatePragmaDisableDirectiveTrivia(diagnostic, formatNode, needsLeadingEndOfLine: true, needsTrailingEndOfLine: needsTrailingEOL); + ? fixer.CreatePragmaRestoreDirectiveTrivia(diagnostic, formatNode, needsLeadingEndOfLine: true, needsTrailingEndOfLine: needsTrailingEOL, cancellationToken) + : fixer.CreatePragmaDisableDirectiveTrivia(diagnostic, formatNode, needsLeadingEndOfLine: true, needsTrailingEndOfLine: needsTrailingEOL, cancellationToken); if (isEOF) { diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs index 3ceb8b0e9ddcf..bb2f8de920e15 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaWarningCodeAction.cs @@ -16,12 +16,14 @@ internal sealed class PragmaWarningCodeAction : AbstractSuppressionCodeAction, I { private readonly SuppressionTargetInfo _suppressionTargetInfo; private readonly Document _document; + private readonly SyntaxFormattingOptions _options; private readonly Diagnostic _diagnostic; private readonly bool _forFixMultipleContext; public static PragmaWarningCodeAction Create( SuppressionTargetInfo suppressionTargetInfo, Document document, + SyntaxFormattingOptions options, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer) { @@ -29,12 +31,13 @@ public static PragmaWarningCodeAction Create( // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token). PragmaHelpers.NormalizeTriviaOnTokens(fixer, ref document, ref suppressionTargetInfo); - return new PragmaWarningCodeAction(suppressionTargetInfo, document, diagnostic, fixer); + return new PragmaWarningCodeAction(suppressionTargetInfo, document, options, diagnostic, fixer); } private PragmaWarningCodeAction( SuppressionTargetInfo suppressionTargetInfo, Document document, + SyntaxFormattingOptions options, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) @@ -42,12 +45,14 @@ private PragmaWarningCodeAction( { _suppressionTargetInfo = suppressionTargetInfo; _document = document; + _options = options; _diagnostic = diagnostic; _forFixMultipleContext = forFixMultipleContext; } public PragmaWarningCodeAction CloneForFixMultipleContext() - => new(_suppressionTargetInfo, _document, _diagnostic, Fixer, forFixMultipleContext: true); + => new(_suppressionTargetInfo, _document, _options, _diagnostic, Fixer, forFixMultipleContext: true); + protected override string DiagnosticIdForEquivalenceKey => _forFixMultipleContext ? string.Empty : _diagnostic.Id; @@ -63,13 +68,13 @@ public async Task GetChangedDocumentAsync(bool includeStartTokenChange (startToken, currentDiagnosticSpan) => { return includeStartTokenChange - ? PragmaHelpers.GetNewStartTokenWithAddedPragma(startToken, currentDiagnosticSpan, _diagnostic, Fixer, FormatNode) + ? PragmaHelpers.GetNewStartTokenWithAddedPragma(startToken, currentDiagnosticSpan, _diagnostic, Fixer, FormatNode, isRemoveSuppression: false, cancellationToken) : startToken; }, (endToken, currentDiagnosticSpan) => { return includeEndTokenChange - ? PragmaHelpers.GetNewEndTokenWithAddedPragma(endToken, currentDiagnosticSpan, _diagnostic, Fixer, FormatNode) + ? PragmaHelpers.GetNewEndTokenWithAddedPragma(endToken, currentDiagnosticSpan, _diagnostic, Fixer, FormatNode, isRemoveSuppression: false, cancellationToken) : endToken; }, cancellationToken).ConfigureAwait(false); @@ -78,8 +83,8 @@ public async Task GetChangedDocumentAsync(bool includeStartTokenChange public SyntaxToken StartToken_TestOnly => _suppressionTargetInfo.StartToken; public SyntaxToken EndToken_TestOnly => _suppressionTargetInfo.EndToken; - private SyntaxNode FormatNode(SyntaxNode node) - => Formatter.Format(node, _document.Project.Solution.Workspace); + private SyntaxNode FormatNode(SyntaxNode node, CancellationToken cancellationToken) + => Formatter.Format(node, _document.Project.Solution.Workspace.Services, _options, cancellationToken); } } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.cs index 52df1bf737b14..c1d861e38b421 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Formatting; namespace Microsoft.CodeAnalysis.CodeFixes.Suppression { @@ -35,7 +36,8 @@ public static async Task CreateAsync( } else if (documentOpt != null && !SuppressionHelpers.IsSynthesizedExternalSourceDiagnostic(diagnostic)) { - return PragmaRemoveAction.Create(suppressionTargetInfo, documentOpt, diagnostic, fixer); + var options = await SyntaxFormattingOptions.FromDocumentAsync(documentOpt, cancellationToken).ConfigureAwait(false); + return PragmaRemoveAction.Create(suppressionTargetInfo, documentOpt, options, diagnostic, fixer); } else { 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 23155cd268212..856de08fb5619 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs @@ -25,11 +25,13 @@ internal abstract partial class RemoveSuppressionCodeAction private class PragmaRemoveAction : RemoveSuppressionCodeAction, IPragmaBasedCodeAction { private readonly Document _document; + private readonly SyntaxFormattingOptions _options; private readonly SuppressionTargetInfo _suppressionTargetInfo; public static PragmaRemoveAction Create( SuppressionTargetInfo suppressionTargetInfo, Document document, + SyntaxFormattingOptions options, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer) { @@ -37,23 +39,25 @@ public static PragmaRemoveAction Create( // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token). PragmaHelpers.NormalizeTriviaOnTokens(fixer, ref document, ref suppressionTargetInfo); - return new PragmaRemoveAction(suppressionTargetInfo, document, diagnostic, fixer); + return new PragmaRemoveAction(suppressionTargetInfo, document, options, diagnostic, fixer); } private PragmaRemoveAction( SuppressionTargetInfo suppressionTargetInfo, Document document, + SyntaxFormattingOptions options, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) : base(diagnostic, fixer, forFixMultipleContext) { _document = document; + _options = options; _suppressionTargetInfo = suppressionTargetInfo; } public override RemoveSuppressionCodeAction CloneForFixMultipleContext() - => new PragmaRemoveAction(_suppressionTargetInfo, _document, _diagnostic, Fixer, forFixMultipleContext: true); + => new PragmaRemoveAction(_suppressionTargetInfo, _document, _options, _diagnostic, Fixer, forFixMultipleContext: true); public override SyntaxTree SyntaxTreeToModify => _suppressionTargetInfo.StartToken.SyntaxTree; @@ -81,11 +85,11 @@ public async Task GetChangedDocumentAsync(bool includeStartTokenChange } SyntaxToken getNewStartToken(SyntaxToken startToken, TextSpan currentDiagnosticSpan) => includeStartTokenChange - ? GetNewTokenWithModifiedPragma(startToken, currentDiagnosticSpan, add, toggle, indexOfLeadingPragmaDisableToRemove, isStartToken: true) + ? GetNewTokenWithModifiedPragma(startToken, currentDiagnosticSpan, add, toggle, indexOfLeadingPragmaDisableToRemove, isStartToken: true, cancellationToken) : startToken; SyntaxToken getNewEndToken(SyntaxToken endToken, TextSpan currentDiagnosticSpan) => includeEndTokenChange - ? GetNewTokenWithModifiedPragma(endToken, currentDiagnosticSpan, add, toggle, indexOfTrailingPragmaEnableToRemove, isStartToken: false) + ? GetNewTokenWithModifiedPragma(endToken, currentDiagnosticSpan, add, toggle, indexOfTrailingPragmaEnableToRemove, isStartToken: false, cancellationToken) : endToken; return await PragmaHelpers.GetChangeDocumentWithPragmaAdjustedAsync( @@ -151,22 +155,22 @@ private static bool CanRemovePragmaTrivia(SyntaxToken token, Diagnostic diagnost return false; } - private SyntaxToken GetNewTokenWithModifiedPragma(SyntaxToken token, TextSpan currentDiagnosticSpan, bool add, bool toggle, int indexOfTriviaToRemoveOrToggle, bool isStartToken) + private SyntaxToken GetNewTokenWithModifiedPragma(SyntaxToken token, TextSpan currentDiagnosticSpan, bool add, bool toggle, int indexOfTriviaToRemoveOrToggle, bool isStartToken, CancellationToken cancellationToken) { return add - ? GetNewTokenWithAddedPragma(token, currentDiagnosticSpan, isStartToken) + ? GetNewTokenWithAddedPragma(token, currentDiagnosticSpan, isStartToken, cancellationToken) : GetNewTokenWithRemovedOrToggledPragma(token, indexOfTriviaToRemoveOrToggle, isStartToken, toggle); } - private SyntaxToken GetNewTokenWithAddedPragma(SyntaxToken token, TextSpan currentDiagnosticSpan, bool isStartToken) + private SyntaxToken GetNewTokenWithAddedPragma(SyntaxToken token, TextSpan currentDiagnosticSpan, bool isStartToken, CancellationToken cancellationToken) { if (isStartToken) { - return PragmaHelpers.GetNewStartTokenWithAddedPragma(token, currentDiagnosticSpan, _diagnostic, Fixer, FormatNode, isRemoveSuppression: true); + return PragmaHelpers.GetNewStartTokenWithAddedPragma(token, currentDiagnosticSpan, _diagnostic, Fixer, FormatNode, isRemoveSuppression: true, cancellationToken); } else { - return PragmaHelpers.GetNewEndTokenWithAddedPragma(token, currentDiagnosticSpan, _diagnostic, Fixer, FormatNode, isRemoveSuppression: true); + return PragmaHelpers.GetNewEndTokenWithAddedPragma(token, currentDiagnosticSpan, _diagnostic, Fixer, FormatNode, isRemoveSuppression: true, cancellationToken); } } @@ -213,8 +217,8 @@ private async Task IsDiagnosticSuppressedBeforeLeadingPragmaAsync(int inde public SyntaxToken StartToken_TestOnly => _suppressionTargetInfo.StartToken; public SyntaxToken EndToken_TestOnly => _suppressionTargetInfo.EndToken; - private SyntaxNode FormatNode(SyntaxNode node) - => Formatter.Format(node, _document.Project.Solution.Workspace); + private SyntaxNode FormatNode(SyntaxNode node, CancellationToken cancellationToken) + => Formatter.Format(node, _document.Project.Solution.Workspace.Services, _options, cancellationToken); } } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs index 68c9393666f94..0d7875d5989b8 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs @@ -10,9 +10,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -42,16 +43,16 @@ public FixAllProvider GetFixAllProvider() public bool IsFixableDiagnostic(Diagnostic diagnostic) => SuppressionHelpers.CanBeSuppressed(diagnostic) || SuppressionHelpers.CanBeUnsuppressed(diagnostic); - protected abstract SyntaxTriviaList CreatePragmaDisableDirectiveTrivia(Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine); - protected abstract SyntaxTriviaList CreatePragmaRestoreDirectiveTrivia(Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine); + protected abstract SyntaxTriviaList CreatePragmaDisableDirectiveTrivia(Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine, CancellationToken cancellationToken); + protected abstract SyntaxTriviaList CreatePragmaRestoreDirectiveTrivia(Diagnostic diagnostic, Func formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine, CancellationToken cancellationToken); protected abstract SyntaxNode AddGlobalSuppressMessageAttribute( SyntaxNode newRoot, ISymbol targetSymbol, INamedTypeSymbol suppressMessageAttribute, Diagnostic diagnostic, - Workspace workspace, - Compilation compilation, + HostWorkspaceServices services, + SyntaxFormattingOptions options, IAddImportsService addImportsService, CancellationToken cancellationToken); @@ -199,6 +200,7 @@ private async Task> GetSuppressionsAsync( skipSuppressMessage = suppressMessageAttribute == null || !suppressMessageAttribute.IsAttribute(); } + var lazyFormattingOptions = (SyntaxFormattingOptions)null; var result = ArrayBuilder.GetInstance(); foreach (var diagnostic in diagnostics) { @@ -208,7 +210,8 @@ private async Task> GetSuppressionsAsync( if (diagnostic.Location.IsInSource && documentOpt != null) { // pragma warning disable. - nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, diagnostic, this)); + lazyFormattingOptions ??= await SyntaxFormattingOptions.FromDocumentAsync(documentOpt, cancellationToken).ConfigureAwait(false); + nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, lazyFormattingOptions, diagnostic, this)); } // SuppressMessageAttribute suppression is not supported for compiler diagnostics. diff --git a/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs b/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs index 68b6878b458d9..fe5e464a41d8b 100644 --- a/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs +++ b/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs @@ -33,9 +33,11 @@ internal sealed class CodeLensReferencesService : ICodeLensReferencesService /// never actually call into this member. /// private static readonly FindReferencesSearchOptions s_nonParallelSearch = - FindReferencesSearchOptions.Default.With( - @explicit: false, - unidirectionalHierarchyCascade: true); + FindReferencesSearchOptions.Default with + { + Explicit = false, + UnidirectionalHierarchyCascade = true + }; private static async Task FindAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, Func> onResults, Func> onCapped, diff --git a/src/Features/Core/Portable/CodeRefactoringHelpers.cs b/src/Features/Core/Portable/CodeRefactoringHelpers.cs index 3f7eba0acb939..4b1d99a7370dd 100644 --- a/src/Features/Core/Portable/CodeRefactoringHelpers.cs +++ b/src/Features/Core/Portable/CodeRefactoringHelpers.cs @@ -15,60 +15,63 @@ internal static class CodeRefactoringHelpers { /// /// - /// Determines if a is underselected given . + /// Determines if a is under-selected given . /// /// - /// Underselection is defined as omitting whole nodes from either the beginning or the end. It can be used e.g. to detect that - /// following selection `1 + [|2 + 3|]` is underselecting the whole expression node tree. + /// Under-selection is defined as omitting whole nodes from either the beginning or the end. It can be used e.g. + /// to detect that following selection `1 + [|2 + 3|]` is under-selecting the whole expression node tree. /// /// - /// Returns false if only and precisely one is selected. In that case the - /// is treated more as a caret location. + /// Returns false if only and precisely one is selected. In that case the is treated more as a caret location. /// /// - /// It's intended to be used in conjunction with - /// that, for non-empty selections, returns the smallest encompassing node. A node that can, for certain refactorings, be too large given user-selection even though - /// it is the smallest that can be retrieved. + /// It's intended to be used in conjunction with that, for non-empty selections, returns the smallest encompassing node. A node that + /// can, for certain refactorings, be too large given user-selection even though it is the smallest that can be + /// retrieved. /// /// - /// When doesn't intersect the node in any way it's not considered to be underselected. + /// When doesn't intersect the node in any way it's not considered to be + /// under-selected. /// /// - /// Null node is always considered underselected. + /// Null node is always considered under-selected. /// /// public static bool IsNodeUnderselected(SyntaxNode? node, TextSpan selection) { - // Selection is null -> it's always underselected - // REASON: Easier API use -> underselected node, don't work on it further + // Selection is null -> it's always under-selected + // REASON: Easier API use -> under-selected node, don't work on it further if (node == null) { return true; } - // Selection or node is empty -> can't be underselected + // Selection or node is empty -> can't be under-selected if (selection.IsEmpty || node.Span.IsEmpty) { return false; } - // Selection is larger than node.Span -> can't be underselecting + // Selection is larger than node.Span -> can't be under-selecting if (selection.Contains(node.Span)) { return false; } - // Selection doesn't intersect node -> can't be underselecting. + // Selection doesn't intersect node -> can't be under-selecting. // RATIONALE: If there's no intersection then we got the node in some other way, e.g. // extracting it after user selected `;` at the end of an expression statement - // `foo()[|;|]` for `foo()` node. + // `goo()[|;|]` for `goo()` node. if (!node.FullSpan.OverlapsWith(selection)) { return false; } // Only precisely one token of the node is selected -> treat is as empty selection -> not - // underselected. The rationale is that if only one Token is selected then the selection + // under-selected. The rationale is that if only one Token is selected then the selection // wasn't about precisely getting the one node and nothing else & therefore we should treat // it as empty selection. if (node.FullSpan.Contains(selection.Start)) @@ -85,10 +88,10 @@ public static bool IsNodeUnderselected(SyntaxNode? node, TextSpan selection) RoslynDebug.Assert(beginningNode is object); RoslynDebug.Assert(endNode is object); - // Node is underselected if either the first (lowest) child doesn't contain start of selection + // Node is under-selected if either the first (lowest) child doesn't contain start of selection // of the last child doesn't intersect with the end. - // Node is underselected if either the first (lowest) child ends before the selection has started + // Node is under-selected if either the first (lowest) child ends before the selection has started // or the last child starts after the selection ends (i.e. one of them is completely on the outside of selection). // It's a crude heuristic but it allows omitting parts of nodes or trivial tokens from the beginning/end // but fires up e.g.: `1 + [|2 + 3|]`. diff --git a/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs b/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs index 9520492d8f040..63e32dbb7ac74 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs @@ -26,19 +26,33 @@ internal abstract class AbstractRefactoringHelpersService> GetRelevantNodesAsync( - Document document, TextSpan selectionRaw, - CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode + Document document, TextSpan selectionRaw, bool allowEmptyNodes, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode + { + using var _1 = ArrayBuilder.GetInstance(out var relevantNodesBuilder); + await AddRelevantNodesAsync(document, selectionRaw, relevantNodesBuilder, cancellationToken).ConfigureAwait(false); + + if (allowEmptyNodes) + return relevantNodesBuilder.ToImmutable(); + + using var _2 = ArrayBuilder.GetInstance(out var nonEmptyNodes); + foreach (var node in relevantNodesBuilder) + { + if (node.Span.Length > 0) + nonEmptyNodes.Add(node); + } + + return nonEmptyNodes.ToImmutable(); + } + + private async Task AddRelevantNodesAsync( + Document document, TextSpan selectionRaw, ArrayBuilder relevantNodesBuilder, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { // Given selection is trimmed first to enable over-selection that spans multiple lines. Since trailing whitespace ends // at newline boundary over-selection to e.g. a line after LocalFunctionStatement would cause FindNode to find enclosing // block's Node. That is because in addition to LocalFunctionStatement the selection would also contain trailing trivia // (whitespace) of following statement. - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - if (root == null) - { - return ImmutableArray.Empty; - } + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService(); var headerFacts = document.GetRequiredLanguageService(); @@ -50,11 +64,7 @@ public async Task> GetRelevantNodesAsync.Empty; - } - - using var relevantNodesBuilderDisposer = ArrayBuilder.GetInstance(out var relevantNodesBuilder); + return; // Every time a Node is considered an extractNodes method is called to add all nodes around the original one // that should also be considered. @@ -124,8 +134,6 @@ public async Task> GetRelevantNodesAsync() where TSyntaxNode : SyntaxNode @@ -230,7 +238,12 @@ static bool IsAcceptableLineDistanceAway( } } - private void AddNodesForTokenToLeft(ISyntaxFactsService syntaxFacts, ArrayBuilder relevantNodesBuilder, int location, SyntaxToken tokenToLeft, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode + private void AddNodesForTokenToLeft( + ISyntaxFactsService syntaxFacts, + ArrayBuilder relevantNodesBuilder, + int location, + SyntaxToken tokenToLeft, + CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { // there could be multiple (n) tokens to the left if first n-1 are Empty -> iterate over all of them while (tokenToLeft != default) @@ -257,7 +270,13 @@ private void AddNodesForTokenToLeft(ISyntaxFactsService syntaxFacts } } - private void AddNodesForTokenToRightOrIn(ISyntaxFactsService syntaxFacts, SyntaxNode root, ArrayBuilder relevantNodesBuilder, int location, SyntaxToken tokenToRightOrIn, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode + private void AddNodesForTokenToRightOrIn( + ISyntaxFactsService syntaxFacts, + SyntaxNode root, + ArrayBuilder relevantNodesBuilder, + int location, + SyntaxToken tokenToRightOrIn, + CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { if (tokenToRightOrIn != default) { @@ -295,7 +314,12 @@ private void AddNodesForTokenToRightOrIn(ISyntaxFactsService syntax } } - private void AddRelevantNodesForSelection(ISyntaxFactsService syntaxFacts, SyntaxNode root, TextSpan selectionTrimmed, ArrayBuilder relevantNodesBuilder, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode + private void AddRelevantNodesForSelection( + ISyntaxFactsService syntaxFacts, + SyntaxNode root, + TextSpan selectionTrimmed, + ArrayBuilder relevantNodesBuilder, + CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { var selectionNode = root.FindNode(selectionTrimmed, getInnermostNodeForTie: true); var prevNode = selectionNode; @@ -456,7 +480,8 @@ protected virtual IEnumerable ExtractNodesInHeader(SyntaxNode root, } protected virtual async Task AddNodesDeepInAsync( - Document document, int position, + Document document, + int position, ArrayBuilder relevantNodesBuilder, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { @@ -496,14 +521,12 @@ protected virtual async Task AddNodesDeepInAsync( } } - private static void AddNonHiddenCorrectTypeNodes(IEnumerable nodes, ArrayBuilder resultBuilder, CancellationToken cancellationToken) - where TSyntaxNode : SyntaxNode + private static void AddNonHiddenCorrectTypeNodes( + IEnumerable nodes, ArrayBuilder resultBuilder, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { var correctTypeNonHiddenNodes = nodes.OfType().Where(n => !n.OverlapsHiddenPosition(cancellationToken)); foreach (var nodeToBeAdded in correctTypeNonHiddenNodes) - { resultBuilder.Add(nodeToBeAdded); - } } public bool IsOnTypeHeader(SyntaxNode root, int position, bool fullHeader, [NotNullWhen(true)] out SyntaxNode? typeDeclaration) diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs index 55d6bdcacbbb5..5c6001c3ddea6 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Options; @@ -28,9 +29,9 @@ internal abstract class AbstractAddMissingImportsFeatureService : IAddMissingImp protected abstract ImmutableArray FixableDiagnosticIds { get; } /// - public async Task AddMissingImportsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + public async Task AddMissingImportsAsync(Document document, TextSpan textSpan, AddMissingImportsOptions options, CancellationToken cancellationToken) { - var analysisResult = await AnalyzeAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + var analysisResult = await AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); return await AddMissingImportsAsync(document, analysisResult, cancellationToken).ConfigureAwait(false); } @@ -48,7 +49,7 @@ public async Task AddMissingImportsAsync(Document document, AddMissing } /// - public async Task AnalyzeAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + public async Task AnalyzeAsync(Document document, TextSpan textSpan, AddMissingImportsOptions options, CancellationToken cancellationToken) { // Get the diagnostics that indicate a missing import. var addImportFeatureService = document.GetRequiredLanguageService(); @@ -59,9 +60,14 @@ public async Task AnalyzeAsync(Document documen // Since we are not currently considering NuGet packages, pass an empty array var packageSources = ImmutableArray.Empty; + var addImportOptions = new AddImportOptions( + SearchOptions: new(SearchReferenceAssemblies: true, SearchNuGetPackages: false), + HideAdvancedMembers: options.HideAdvancedMembers, + Placement: options.Placement); + var unambiguousFixes = await addImportFeatureService.GetUniqueFixesAsync( document, textSpan, FixableDiagnosticIds, symbolSearchService, - searchReferenceAssemblies: true, packageSources, cancellationToken).ConfigureAwait(false); + addImportOptions, packageSources, cancellationToken).ConfigureAwait(false); // We do not want to add project or framework references without the user's input, so filter those out. var usableFixes = unambiguousFixes.WhereAsArray(fixData => DoesNotAddReference(fixData, document.Project.Id)); @@ -140,8 +146,7 @@ private static async Task ApplyFixesAsync(Document document, Immutable private static async Task CleanUpNewLinesAsync(Document document, IEnumerable insertSpans, CancellationToken cancellationToken) { - var languageFormatter = document.GetRequiredLanguageService(); - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var options = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); var newDocument = document; @@ -150,21 +155,19 @@ private static async Task CleanUpNewLinesAsync(Document document, IEnu // to separate the import section from the other content. foreach (var insertSpan in insertSpans) { - newDocument = await CleanUpNewLinesAsync(newDocument, insertSpan, languageFormatter, options, cancellationToken).ConfigureAwait(false); + newDocument = await CleanUpNewLinesAsync(newDocument, insertSpan, options, cancellationToken).ConfigureAwait(false); } return newDocument; } - private static async Task CleanUpNewLinesAsync(Document document, TextSpan insertSpan, ISyntaxFormattingService languageFormatter, OptionSet optionSet, CancellationToken cancellationToken) + private static async Task CleanUpNewLinesAsync(Document document, TextSpan insertSpan, SyntaxFormattingOptions options, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var optionService = document.Project.Solution.Workspace.Services.GetRequiredService(); - var shouldUseFormattingSpanCollapse = optionSet.GetOption(FormattingBehaviorOptions.AllowDisjointSpanMerging); - var options = optionSet.AsAnalyzerConfigOptions(optionService, root.Language); + var services = document.Project.Solution.Workspace.Services; - var textChanges = languageFormatter.Format(root, new[] { insertSpan }, shouldUseFormattingSpanCollapse, options, new[] { new CleanUpNewLinesFormatter(text) }, cancellationToken).GetTextChanges(cancellationToken); + var textChanges = Formatter.GetFormattedTextChanges(root, new[] { insertSpan }, services, options, rules: new[] { new CleanUpNewLinesFormatter(text) }, cancellationToken); // If there are no changes then, do less work. if (textChanges.Count == 0) diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs index 1917ba0a01f11..b7f78d536b1ea 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs @@ -7,7 +7,10 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.PasteTracking; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -36,7 +39,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // Check pasted text span for missing imports var addMissingImportsService = document.GetLanguageService(); - var analysis = await addMissingImportsService.AnalyzeAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + var placement = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var options = new AddMissingImportsOptions(context.Options.HideAdvancedMembers, placement); + + var analysis = await addMissingImportsService.AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); if (!analysis.CanAddMissingImports) { return; diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs index a05c56f33d20e..7cb68cf7d3cd9 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs @@ -2,13 +2,21 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.AddMissingImports { + [DataContract] + internal readonly record struct AddMissingImportsOptions( + [property: DataMember(Order = 0)] bool HideAdvancedMembers, + [property: DataMember(Order = 1)] AddImportPlacementOptions Placement); + internal interface IAddMissingImportsFeatureService : ILanguageService { /// @@ -17,15 +25,15 @@ internal interface IAddMissingImportsFeatureService : ILanguageService /// if there are ambiguous imports, no known resolutions to import, or if no imports that would be provided /// would be added without adding a reference for the project. /// - Task AddMissingImportsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); + Task AddMissingImportsAsync(Document document, TextSpan textSpan, AddMissingImportsOptions options, CancellationToken cancellationToken); /// /// Analyzes the document inside the texstpan to determine if imports can be added. /// - Task AnalyzeAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); + Task AnalyzeAsync(Document document, TextSpan textSpan, AddMissingImportsOptions options, CancellationToken cancellationToken); /// - /// Performs the same action as but + /// Performs the same action as but /// with a predetermined analysis of the input instead of recalculating it /// Task AddMissingImportsAsync(Document document, AddMissingImportsAnalysisResult analysisResult, CancellationToken cancellationToken); diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringContextExtensions.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringContextExtensions.cs index aab79cb1b7829..5d9d1afd2bfa9 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringContextExtensions.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringContextExtensions.cs @@ -18,7 +18,7 @@ internal static class CodeRefactoringContextExtensions /// /// Use this helper to register multiple refactorings (). /// - internal static void RegisterRefactorings( + public static void RegisterRefactorings( this CodeRefactoringContext context, ImmutableArray actions, TextSpan? applicableToSpan = null) where TCodeAction : CodeAction { @@ -38,31 +38,36 @@ internal static void RegisterRefactorings( } } - internal static Task TryGetRelevantNodeAsync(this CodeRefactoringContext context) - where TSyntaxNode : SyntaxNode - => TryGetRelevantNodeAsync(context.Document, context.Span, context.CancellationToken); + public static Task TryGetRelevantNodeAsync(this CodeRefactoringContext context) where TSyntaxNode : SyntaxNode + => TryGetRelevantNodeAsync(context, allowEmptyNode: false); - internal static Task> GetRelevantNodesAsync(this CodeRefactoringContext context) - where TSyntaxNode : SyntaxNode - => GetRelevantNodesAsync(context.Document, context.Span, context.CancellationToken); + public static Task TryGetRelevantNodeAsync(this CodeRefactoringContext context, bool allowEmptyNode) where TSyntaxNode : SyntaxNode + => TryGetRelevantNodeAsync(context.Document, context.Span, allowEmptyNode, context.CancellationToken); - internal static async Task TryGetRelevantNodeAsync( - this Document document, - TextSpan span, - CancellationToken cancellationToken) - where TSyntaxNode : SyntaxNode + public static Task> GetRelevantNodesAsync(this CodeRefactoringContext context) where TSyntaxNode : SyntaxNode + => GetRelevantNodesAsync(context, allowEmptyNodes: false); + + public static Task> GetRelevantNodesAsync(this CodeRefactoringContext context, bool allowEmptyNodes) where TSyntaxNode : SyntaxNode + => GetRelevantNodesAsync(context.Document, context.Span, allowEmptyNodes, context.CancellationToken); + + public static Task TryGetRelevantNodeAsync(this Document document, TextSpan span, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode + => TryGetRelevantNodeAsync(document, span, allowEmptyNode: false, cancellationToken); + + public static async Task TryGetRelevantNodeAsync(this Document document, TextSpan span, bool allowEmptyNode, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { - var potentialNodes = await GetRelevantNodesAsync(document, span, cancellationToken).ConfigureAwait(false); + var potentialNodes = await GetRelevantNodesAsync(document, span, allowEmptyNode, cancellationToken).ConfigureAwait(false); return potentialNodes.FirstOrDefault(); } - internal static Task> GetRelevantNodesAsync( - this Document document, - TextSpan span, - CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode + public static Task> GetRelevantNodesAsync( + this Document document, TextSpan span, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode + => GetRelevantNodesAsync(document, span, allowEmptyNodes: false, cancellationToken); + + public static Task> GetRelevantNodesAsync( + this Document document, TextSpan span, bool allowEmptyNodes, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { var helpers = document.GetRequiredLanguageService(); - return helpers.GetRelevantNodesAsync(document, span, cancellationToken); + return helpers.GetRelevantNodesAsync(document, span, allowEmptyNodes, cancellationToken); } } } diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index 4fd43ca55d7b3..cfb19127cff22 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings { [Export(typeof(ICodeRefactoringService)), Shared] - internal class CodeRefactoringService : ICodeRefactoringService + internal sealed class CodeRefactoringService : ICodeRefactoringService { private readonly Lazy>>> _lazyLanguageToProvidersMap; private readonly Lazy> _lazyRefactoringToMetadataMap; @@ -84,6 +84,7 @@ private ConcatImmutableArray GetProviders(Document docu public async Task HasRefactoringsAsync( Document document, TextSpan state, + CodeActionOptions options, CancellationToken cancellationToken) { var extensionManager = document.Project.Solution.Workspace.Services.GetRequiredService(); @@ -94,7 +95,7 @@ public async Task HasRefactoringsAsync( RefactoringToMetadataMap.TryGetValue(provider, out var providerMetadata); var refactoring = await GetRefactoringFromProviderAsync( - document, state, provider, providerMetadata, extensionManager, isBlocking: false, cancellationToken).ConfigureAwait(false); + document, state, provider, providerMetadata, extensionManager, options, cancellationToken).ConfigureAwait(false); if (refactoring != null) { @@ -109,7 +110,7 @@ public async Task> GetRefactoringsAsync( Document document, TextSpan state, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken) { @@ -131,7 +132,7 @@ public async Task> GetRefactoringsAsync( using (addOperationScope(providerName)) using (RoslynEventSource.LogInformationalBlock(FunctionId.Refactoring_CodeRefactoringService_GetRefactoringsAsync, providerName, cancellationToken)) { - return GetRefactoringFromProviderAsync(document, state, provider, providerMetadata, extensionManager, isBlocking, cancellationToken); + return GetRefactoringFromProviderAsync(document, state, provider, providerMetadata, extensionManager, options, cancellationToken); } }, cancellationToken)); @@ -148,7 +149,7 @@ public async Task> GetRefactoringsAsync( CodeRefactoringProvider provider, CodeChangeProviderMetadata? providerMetadata, IExtensionManager extensionManager, - bool isBlocking, + CodeActionOptions options, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -176,7 +177,7 @@ public async Task> GetRefactoringsAsync( actions.Add((action, applicableToSpan)); } }, - isBlocking, + options, cancellationToken); var task = provider.ComputeRefactoringsAsync(context) ?? Task.CompletedTask; diff --git a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs index 840c4835d72d4..0e43a48d39e56 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs @@ -13,17 +13,14 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings { internal interface ICodeRefactoringService { - Task HasRefactoringsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); + Task HasRefactoringsAsync(Document document, TextSpan textSpan, CodeActionOptions options, CancellationToken cancellationToken); - Task> GetRefactoringsAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); + Task> GetRefactoringsAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken); } internal static class ICodeRefactoringServiceExtensions { - public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, CancellationToken cancellationToken) - => service.GetRefactoringsAsync(document, state, isBlocking: false, cancellationToken); - - public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, bool isBlocking, CancellationToken cancellationToken) - => service.GetRefactoringsAsync(document, state, CodeActionRequestPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); + public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, CodeActionOptions options, CancellationToken cancellationToken) + => service.GetRefactoringsAsync(document, state, CodeActionRequestPriority.None, options, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs b/src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs index 48365e2ba30d5..d9317ebd1a832 100644 --- a/src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs @@ -26,28 +26,42 @@ internal interface IRefactoringHelpersService : IHeaderFactsService, ILanguageSe /// /// - /// Returns an array of instances for refactoring given specified selection in document. + /// Returns an array of instances for refactoring given specified selection + /// in document. determines if the returned nodes will can have empty spans + /// or not. /// /// - /// A instance is returned if: - /// - Selection is zero-width and inside/touching a Token with direct parent of type . - /// - Selection is zero-width and touching a Token whose ancestor of type ends/starts precisely on current selection. - /// - Selection is zero-width and in whitespace that corresponds to a Token whose direct ancestor is of type of type . - /// - Selection is zero-width and in a header (defined by ISyntaxFacts helpers) of an node of type of type . - /// - Token whose direct parent of type is selected. - /// - Selection is zero-width and wanted node is an expression / argument with selection within such syntax node (arbitrarily deep) on its first line. - /// - Whole node of a type is selected. + /// A instance is returned if: - Selection is zero-width and inside/touching + /// a Token with direct parent of type . - Selection is zero-width and + /// touching a Token whose ancestor of type ends/starts precisely on current + /// selection. - Selection is zero-width and in whitespace that corresponds to a Token whose direct ancestor is + /// of type of type . - Selection is zero-width and in a header (defined by + /// ISyntaxFacts helpers) of an node of type of type . - Token whose direct + /// parent of type is selected. - Selection is zero-width and wanted node is + /// an expression / argument with selection within such syntax node (arbitrarily deep) on its first line. - + /// Whole node of a type is selected. /// /// - /// Attempts extracting a Node of type for each Node it considers (see above). - /// E.g. extracts initializer expressions from declarations and assignments, Property declaration from any header node, etc. + /// Attempts extracting a Node of type for each Node it considers (see + /// above). E.g. extracts initializer expressions from declarations and assignments, Property declaration from + /// any header node, etc. /// /// - /// Note: this function trims all whitespace from both the beginning and the end of given . - /// The trimmed version is then used to determine relevant . It also handles incomplete selections - /// of tokens gracefully. Over-selection containing leading comments is also handled correctly. + /// Note: this function trims all whitespace from both the beginning and the end of given . The trimmed version is then used to determine relevant . It also + /// handles incomplete selections of tokens gracefully. Over-selection containing leading comments is also + /// handled correctly. /// /// - Task> GetRelevantNodesAsync(Document document, TextSpan selection, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode; + Task> GetRelevantNodesAsync(Document document, TextSpan selection, bool allowEmptyNodes, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode; + } + + internal static class IRefactoringHelpersServiceExtensions + { + public static Task> GetRelevantNodesAsync( + this IRefactoringHelpersService service, Document document, TextSpan selection, CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode + { + return service.GetRelevantNodesAsync(document, selection, allowEmptyNodes: false, cancellationToken); + } } } diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs index b6851ee61c69d..e3b26f9ab08de 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs @@ -29,8 +29,7 @@ public override async Task GetModifiedSolutionAsync() // if no such conflicts exist, proceed with RenameSymbolAsync. var solution = SemanticDocument.Document.Project.Solution; var symbol = State.SemanticDocument.SemanticModel.GetDeclaredSymbol(State.TypeNode, CancellationToken); - var documentOptions = await SemanticDocument.Document.GetOptionsAsync(CancellationToken).ConfigureAwait(false); - return await Renamer.RenameSymbolAsync(solution, symbol, FileName, documentOptions, CancellationToken).ConfigureAwait(false); + return await Renamer.RenameSymbolAsync(solution, symbol, new SymbolRenameOptions(), FileName, CancellationToken).ConfigureAwait(false); } } } diff --git a/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs b/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs index 69248865fcff5..af59dc55326cf 100644 --- a/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs +++ b/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs @@ -30,6 +30,7 @@ internal static class PredefinedCodeRefactoringProviderNames public const string ConvertNumericLiteral = nameof(ConvertNumericLiteral); public const string ConvertPlaceholderToInterpolatedString = nameof(ConvertPlaceholderToInterpolatedString); public const string ConvertToInterpolatedString = "Convert To Interpolated String Code Action Provider"; + public const string ConvertToRawString = nameof(ConvertToRawString); public const string ConvertTryCastToDirectCast = "Convert Try Cast to Direct Cast"; public const string ConvertTupleToStruct = "Convert Tuple to Struct Code Action Provider"; public const string EnableNullable = "Enable Nullable Reference Types"; diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs index d4c89edca9c7a..925e0c51308fc 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs @@ -11,7 +11,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Formatting; @@ -606,14 +607,14 @@ private async Task FixDeclarationDocumentAsync( var namesToImport = GetAllNamespaceImportsForDeclaringDocument(oldNamespace, newNamespace); var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var allowInHiddenRegions = document.CanAddImportsInHiddenRegions(); + var addImportsOptions = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); var documentWithAddedImports = await AddImportsInContainersAsync( document, addImportService, containersToAddImports, namesToImport, - allowInHiddenRegions, + addImportsOptions, cancellationToken).ConfigureAwait(false); var root = await documentWithAddedImports.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -622,7 +623,9 @@ private async Task FixDeclarationDocumentAsync( .WithAdditionalAnnotations(Formatter.Annotation); // Need to invoke formatter explicitly since we are doing the diff merge ourselves. - root = Formatter.Format(root, Formatter.Annotation, documentWithAddedImports.Project.Solution.Workspace, optionSet, cancellationToken); + var services = documentWithAddedImports.Project.Solution.Workspace.Services; + var formattingOptions = SyntaxFormattingOptions.Create(optionSet, services, root.Language); + root = Formatter.Format(root, Formatter.Annotation, services, formattingOptions, cancellationToken); root = root.WithAdditionalAnnotations(Simplifier.Annotation); var formattedDocument = documentWithAddedImports.WithSyntaxRoot(root); @@ -649,14 +652,14 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref .ConfigureAwait(false); var optionSet = await documentWithRefFixed.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var allowInHiddenRegions = document.CanAddImportsInHiddenRegions(); + var addImportsOptions = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); var documentWithAdditionalImports = await AddImportsInContainersAsync( documentWithRefFixed, addImportService, containers, ImmutableArray.Create(newNamespace), - allowInHiddenRegions, + addImportsOptions, cancellationToken).ConfigureAwait(false); // Need to invoke formatter explicitly since we are doing the diff merge ourselves. @@ -688,6 +691,7 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref var generator = SyntaxGenerator.GetGenerator(document); var syntaxFacts = document.GetRequiredLanguageService(); + var codeGenerator = document.GetRequiredLanguageService(); // We need a dummy import to figure out the container for given reference. var dummyImport = CreateImport(generator, "Dummy", withFormatterAnnotation: false); @@ -728,9 +732,10 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref } } - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var addImportsOptions = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + // Use a dummy import node to figure out which container the new import will be added to. - var container = addImportService.GetImportContainer(root, refNode, dummyImport, options); + var container = addImportService.GetImportContainer(root, refNode, dummyImport, addImportsOptions); containers.Add(container); } @@ -808,7 +813,7 @@ private static async Task AddImportsInContainersAsync( IAddImportsService addImportService, ImmutableArray containers, ImmutableArray names, - bool allowInHiddenRegions, + AddImportPlacementOptions options, CancellationToken cancellationToken) { // Sort containers based on their span start, to make the result of @@ -818,7 +823,7 @@ private static async Task AddImportsInContainersAsync( containers = containers.Sort(SyntaxNodeSpanStartComparer.Instance); } - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var generator = document.GetRequiredLanguageService(); var imports = CreateImports(document, names, withFormatterAnnotation: true); foreach (var container in containers) @@ -832,8 +837,7 @@ private static async Task AddImportsInContainersAsync( var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var generator = document.GetRequiredLanguageService(); - root = addImportService.AddImports(compilation, root, contextLocation, imports, generator, options, allowInHiddenRegions, cancellationToken); + root = addImportService.AddImports(compilation, root, contextLocation, imports, generator, options, cancellationToken); document = document.WithSyntaxRoot(root); } diff --git a/src/Features/Core/Portable/Common/DelayTimeSpan.cs b/src/Features/Core/Portable/Common/DelayTimeSpan.cs new file mode 100644 index 0000000000000..59d9aa6100664 --- /dev/null +++ b/src/Features/Core/Portable/Common/DelayTimeSpan.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; + +namespace Microsoft.CodeAnalysis +{ + internal static class DelayTimeSpan + { + public static readonly TimeSpan NearImmediate = TimeSpan.FromMilliseconds(50); + public static readonly TimeSpan Short = TimeSpan.FromMilliseconds(250); + public static readonly TimeSpan Medium = TimeSpan.FromMilliseconds(500); + public static readonly TimeSpan Idle = TimeSpan.FromMilliseconds(1500); + public static readonly TimeSpan NonFocus = TimeSpan.FromMilliseconds(3000); + } +} diff --git a/src/Features/Core/Portable/Completion/ArgumentContext.cs b/src/Features/Core/Portable/Completion/ArgumentContext.cs index 4edb328201163..7f88525a5139a 100644 --- a/src/Features/Core/Portable/Completion/ArgumentContext.cs +++ b/src/Features/Core/Portable/Completion/ArgumentContext.cs @@ -4,6 +4,7 @@ using System; using System.Threading; +using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Completion { @@ -14,6 +15,7 @@ internal sealed class ArgumentContext { public ArgumentContext( ArgumentProvider provider, + OptionSet options, SemanticModel semanticModel, int position, IParameterSymbol parameter, @@ -21,6 +23,7 @@ public ArgumentContext( CancellationToken cancellationToken) { Provider = provider ?? throw new ArgumentNullException(nameof(provider)); + Options = options ?? throw new ArgumentNullException(nameof(options)); SemanticModel = semanticModel ?? throw new ArgumentNullException(nameof(semanticModel)); Position = position; Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter)); @@ -30,6 +33,11 @@ public ArgumentContext( internal ArgumentProvider Provider { get; } + /// + /// Gets the effective options where argument completion is requested. + /// + public OptionSet Options { get; } + /// /// Gets the semantic model where argument completion is requested. /// diff --git a/src/Features/Core/Portable/Completion/CommonCompletionProvider.cs b/src/Features/Core/Portable/Completion/CommonCompletionProvider.cs index d5bff0df2cb65..ad83b030f2978 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionProvider.cs @@ -34,10 +34,12 @@ internal abstract class CommonCompletionProvider : CompletionProvider public sealed override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, OptionSet options) { Debug.Fail("For backwards API compat only, should not be called"); - return ShouldTriggerCompletionImpl(text, caretPosition, trigger, CompletionOptions.From(options, Language)); + + // Publicly available options do not affect this API. + return ShouldTriggerCompletionImpl(text, caretPosition, trigger, CompletionOptions.Default); } - internal override bool ShouldTriggerCompletion(HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options) + internal override bool ShouldTriggerCompletion(HostLanguageServices 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) @@ -54,7 +56,9 @@ public virtual bool IsInsertionTrigger(SourceText text, int insertedCharacterPos public sealed override Task GetDescriptionAsync(Document document, CompletionItem item, CancellationToken cancellationToken) { Debug.Fail("For backwards API compat only, should not be called"); - return GetDescriptionAsync(document, item, CompletionOptions.From(document.Project), SymbolDescriptionOptions.From(document.Project), cancellationToken); + + // Publicly available options do not affect this API. + return GetDescriptionAsync(document, item, CompletionOptions.Default, SymbolDescriptionOptions.Default, cancellationToken); } internal override async Task GetDescriptionAsync(Document document, CompletionItem item, CompletionOptions options, SymbolDescriptionOptions displayOptions, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/Completion/CommonCompletionService.cs b/src/Features/Core/Portable/Completion/CommonCompletionService.cs index a8efbef0a1be7..6f54d8db5db78 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionService.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionService.cs @@ -23,7 +23,7 @@ protected override CompletionItem GetBetterItem(CompletionItem item, CompletionI // We've constructed the export order of completion providers so // that snippets are exported after everything else. That way, // when we choose a single item per display text, snippet - // glyphs appear by snippets. This breaks preselection of items + // glyphs appear by snippets. This breaks pre-selection of items // whose display text is also a snippet (workitem 852578), // the snippet item doesn't have its preselect bit set. // We'll special case this by not preferring later items @@ -36,15 +36,16 @@ protected override CompletionItem GetBetterItem(CompletionItem item, CompletionI return base.GetBetterItem(item, existingItem); } - internal override Task<(CompletionList? completionList, bool expandItemsAvailable)> GetCompletionsInternalAsync( + internal override Task GetCompletionsAsync( Document document, int caretPosition, CompletionOptions options, + OptionSet passThroughOptions, CompletionTrigger trigger, ImmutableHashSet? roles, CancellationToken cancellationToken) { - return GetCompletionsWithAvailabilityOfExpandedItemsAsync(document, caretPosition, trigger, roles, options, cancellationToken); + return GetCompletionsWithAvailabilityOfExpandedItemsAsync(document, caretPosition, options, passThroughOptions, trigger, roles, cancellationToken); } protected static bool IsKeywordItem(CompletionItem item) diff --git a/src/Features/Core/Portable/Completion/CompletionContext.cs b/src/Features/Core/Portable/Completion/CompletionContext.cs index a2faafdc52526..c7f64e56717a0 100644 --- a/src/Features/Core/Portable/Completion/CompletionContext.cs +++ b/src/Features/Core/Portable/Completion/CompletionContext.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; using System.Threading; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; @@ -18,7 +20,7 @@ public sealed class CompletionContext private readonly List _items; private CompletionItem? _suggestionModeItem; - private OptionSet? _lazyOptionSet; + private bool _isExclusive; internal CompletionProvider Provider { get; } @@ -45,15 +47,15 @@ public sealed class CompletionContext /// /// The span of the document the completion list corresponds to. It will be set initially to /// the result of , but it can - /// be overwritten during . The purpose - /// of the span is to: + /// be overwritten during . + /// The purpose of the span is to: /// 1. Signify where the completions should be presented. /// 2. Designate any existing text in the document that should be used for filtering. /// 3. Specify, by default, what portion of the text should be replaced when a completion /// item is committed. /// public TextSpan CompletionListSpan { get; set; } -#pragma warning restore RS0030 // Do not used banned APIs +#pragma warning restore /// /// The triggering action that caused completion to be started. @@ -72,16 +74,28 @@ public sealed class CompletionContext /// /// Set to true if the items added here should be the only items presented to the user. + /// Expand items should never be exclusive. /// - public bool IsExclusive { get; set; } + public bool IsExclusive + { + get + { + return _isExclusive && !Provider.IsExpandItemProvider; + } + + set + { + if (value) + Debug.Assert(!Provider.IsExpandItemProvider); + + _isExclusive = value; + } + } /// - /// Set to true if the corresponding provider can provide extended items with current context, - /// regardless of whether those items are actually added. i.e. it might be disabled by default, - /// but we still want to show the expander so user can explicitly request them to be added to - /// completion list if we are in the appropriate context. + /// The options that completion was started with. /// - internal bool ExpandItemsAvailable { get; set; } + public OptionSet Options { get; } /// /// Creates a instance. @@ -92,17 +106,20 @@ public CompletionContext( int position, TextSpan defaultSpan, CompletionTrigger trigger, - OptionSet options, + OptionSet? options, CancellationToken cancellationToken) : this(provider ?? throw new ArgumentNullException(nameof(provider)), document ?? throw new ArgumentNullException(nameof(document)), position, defaultSpan, trigger, - CompletionOptions.From(options ?? throw new ArgumentNullException(nameof(options)), document.Project.Language), + // Publicly available options do not affect this API. + CompletionOptions.Default, cancellationToken) { - _lazyOptionSet = options; +#pragma warning disable RS0030 // Do not used banned APIs + Options = options ?? OptionValueSet.Empty; +#pragma warning restore } /// @@ -125,13 +142,11 @@ internal CompletionContext( CompletionOptions = options; CancellationToken = cancellationToken; _items = new List(); - } - /// - /// The options that completion was started with. - /// - public OptionSet Options - => _lazyOptionSet ??= CompletionOptions.ToSet(Document.Project.Language); +#pragma warning disable RS0030 // Do not used banned APIs + Options = OptionValueSet.Empty; +#pragma warning restore + } internal IReadOnlyList Items => _items; diff --git a/src/Features/Core/Portable/Completion/CompletionItem.cs b/src/Features/Core/Portable/Completion/CompletionItem.cs index d7a99a5427155..ee534d541c98d 100644 --- a/src/Features/Core/Portable/Completion/CompletionItem.cs +++ b/src/Features/Core/Portable/Completion/CompletionItem.cs @@ -404,7 +404,11 @@ int IComparable.CompareTo([AllowNull] CompletionItem other) return 1; } - // Make sure expanded items are listed after non-expanded ones + // Make sure expanded items are listed after non-expanded ones. + // Note that in our ItemManager at async-completion layer, we implicitly + // rely on this behavior when combining delayed expanded items list with + // non-expanded items (to avoid sorting again). if this changed, we need + // to make sure to sort items properly in ItemManager. var thisIsExpandItem = Flags.IsExpanded(); var otherIsExpandItem = other.Flags.IsExpanded(); diff --git a/src/Features/Core/Portable/Completion/CompletionList.cs b/src/Features/Core/Portable/Completion/CompletionList.cs index 26125fe0ed0d1..539495669bf06 100644 --- a/src/Features/Core/Portable/Completion/CompletionList.cs +++ b/src/Features/Core/Portable/Completion/CompletionList.cs @@ -44,7 +44,7 @@ public sealed class CompletionList /// /// An optional that appears selected in the list presented to the user during suggestion mode. - /// Suggestion mode disables autoselection of items in the list, giving preference to the text typed by the user unless a specific item is selected manually. + /// Suggestion mode disables auto-selection of items in the list, giving preference to the text typed by the user unless a specific item is selected manually. /// Specifying a is a request that the completion host operate in suggestion mode. /// The item specified determines the text displayed and the description associated with it unless a different item is manually selected. /// No text is ever inserted when this item is completed, leaving the text the user typed instead. @@ -157,6 +157,8 @@ public CompletionList WithSuggestionModeItem(CompletionItem suggestionModeItem) default, default, CompletionRules.Default, suggestionModeItem: null, isExclusive: false); + internal bool IsEmpty => Items.IsEmpty && SuggestionModeItem is null; + internal TestAccessor GetTestAccessor() => new(this); diff --git a/src/Features/Core/Portable/Completion/CompletionOptions.cs b/src/Features/Core/Portable/Completion/CompletionOptions.cs index 314b7f592dd79..126887d9b5afb 100644 --- a/src/Features/Core/Portable/Completion/CompletionOptions.cs +++ b/src/Features/Core/Portable/Completion/CompletionOptions.cs @@ -2,201 +2,47 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Composition; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Recommendations; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options.Providers; namespace Microsoft.CodeAnalysis.Completion { - internal record struct CompletionOptions( - bool TriggerOnTyping, - bool TriggerOnTypingLetters, - bool? TriggerOnDeletion, - bool TriggerInArgumentLists, - bool IsExpandedCompletion, - EnterKeyRule EnterKeyBehavior, - SnippetsRule SnippetsBehavior, - bool HideAdvancedMembers, - bool ShowNameSuggestions, - bool? ShowItemsFromUnimportedNamespaces, - bool UnnamedSymbolCompletionDisabled, - bool TargetTypedCompletionFilter, - bool TypeImportCompletion, - bool ProvideDateAndTimeCompletions, - bool ProvideRegexCompletions, - int TimeoutInMillisecondsForExtensionMethodImportCompletion, + internal readonly record struct CompletionOptions( + bool TriggerOnTyping = true, + bool TriggerOnTypingLetters = true, + bool? TriggerOnDeletion = null, + bool TriggerInArgumentLists = true, + EnterKeyRule EnterKeyBehavior = EnterKeyRule.Default, + SnippetsRule SnippetsBehavior = SnippetsRule.Default, + bool HideAdvancedMembers = false, + bool ShowNameSuggestions = true, + bool? ShowItemsFromUnimportedNamespaces = null, + bool UnnamedSymbolCompletionDisabled = false, + bool TargetTypedCompletionFilter = false, + bool TypeImportCompletion = false, + bool ProvideDateAndTimeCompletions = true, + bool ProvideRegexCompletions = true, + bool ForceExpandedCompletionIndexCreation = false, bool FilterOutOfScopeLocals = true, - bool ShowXmlDocCommentCompletion = true) + bool ShowXmlDocCommentCompletion = true, + ExpandedCompletionMode ExpandedCompletionBehavior = ExpandedCompletionMode.AllItems) { - public static readonly CompletionOptions Default - = new( - TriggerOnTyping: Metadata.TriggerOnTyping.DefaultValue, - TriggerOnTypingLetters: Metadata.TriggerOnTypingLetters.DefaultValue, - TriggerOnDeletion: Metadata.TriggerOnDeletion.DefaultValue, - TriggerInArgumentLists: Metadata.TriggerInArgumentLists.DefaultValue, - IsExpandedCompletion: Metadata.IsExpandedCompletion.DefaultValue, - EnterKeyBehavior: Metadata.EnterKeyBehavior.DefaultValue, - SnippetsBehavior: Metadata.SnippetsBehavior.DefaultValue, - HideAdvancedMembers: Metadata.HideAdvancedMembers.DefaultValue, - ShowNameSuggestions: Metadata.ShowNameSuggestions.DefaultValue, - ShowItemsFromUnimportedNamespaces: Metadata.ShowItemsFromUnimportedNamespaces.DefaultValue, - UnnamedSymbolCompletionDisabled: Metadata.UnnamedSymbolCompletionDisabledFeatureFlag.DefaultValue, - TargetTypedCompletionFilter: Metadata.TargetTypedCompletionFilterFeatureFlag.DefaultValue, - TypeImportCompletion: Metadata.TypeImportCompletionFeatureFlag.DefaultValue, - ProvideDateAndTimeCompletions: Metadata.ProvideDateAndTimeCompletions.DefaultValue, - ProvideRegexCompletions: Metadata.ProvideRegexCompletions.DefaultValue, - TimeoutInMillisecondsForExtensionMethodImportCompletion: Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion.DefaultValue); - - public static CompletionOptions From(Project project) - => From(project.Solution.Options, project.Language); - - public static CompletionOptions From(OptionSet options, string language) - => new( - TriggerOnTyping: options.GetOption(Metadata.TriggerOnTyping, language), - TriggerOnTypingLetters: options.GetOption(Metadata.TriggerOnTypingLetters, language), - TriggerOnDeletion: options.GetOption(Metadata.TriggerOnDeletion, language), - TriggerInArgumentLists: options.GetOption(Metadata.TriggerInArgumentLists, language), - IsExpandedCompletion: options.GetOption(Metadata.IsExpandedCompletion), - EnterKeyBehavior: options.GetOption(Metadata.EnterKeyBehavior, language), - SnippetsBehavior: options.GetOption(Metadata.SnippetsBehavior, language), - HideAdvancedMembers: options.GetOption(Metadata.HideAdvancedMembers, language), - ShowNameSuggestions: options.GetOption(Metadata.ShowNameSuggestions, language), - ShowItemsFromUnimportedNamespaces: options.GetOption(Metadata.ShowItemsFromUnimportedNamespaces, language), - UnnamedSymbolCompletionDisabled: options.GetOption(Metadata.UnnamedSymbolCompletionDisabledFeatureFlag), - TargetTypedCompletionFilter: options.GetOption(Metadata.TargetTypedCompletionFilterFeatureFlag), - TypeImportCompletion: options.GetOption(Metadata.TypeImportCompletionFeatureFlag), - ProvideDateAndTimeCompletions: options.GetOption(Metadata.ProvideDateAndTimeCompletions, language), - ProvideRegexCompletions: options.GetOption(Metadata.ProvideRegexCompletions, language), - TimeoutInMillisecondsForExtensionMethodImportCompletion: options.GetOption(Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion)); - - public OptionSet WithChangedOptions(OptionSet set, string language) - => set. - WithChangedOption(Metadata.TriggerOnTyping, language, TriggerOnTyping). - WithChangedOption(Metadata.TriggerOnTypingLetters, language, TriggerOnTypingLetters). - WithChangedOption(Metadata.TriggerOnDeletion, language, TriggerOnDeletion). - WithChangedOption(Metadata.TriggerInArgumentLists, language, TriggerInArgumentLists). - WithChangedOption(Metadata.IsExpandedCompletion, IsExpandedCompletion). - WithChangedOption(Metadata.EnterKeyBehavior, language, EnterKeyBehavior). - WithChangedOption(Metadata.SnippetsBehavior, language, SnippetsBehavior). - WithChangedOption(Metadata.HideAdvancedMembers, language, HideAdvancedMembers). - WithChangedOption(Metadata.ShowNameSuggestions, language, ShowNameSuggestions). - WithChangedOption(Metadata.ShowItemsFromUnimportedNamespaces, language, ShowItemsFromUnimportedNamespaces). - WithChangedOption(Metadata.UnnamedSymbolCompletionDisabledFeatureFlag, UnnamedSymbolCompletionDisabled). - WithChangedOption(Metadata.TargetTypedCompletionFilterFeatureFlag, TargetTypedCompletionFilter). - WithChangedOption(Metadata.TypeImportCompletionFeatureFlag, TypeImportCompletion). - WithChangedOption(Metadata.ProvideDateAndTimeCompletions, language, ProvideDateAndTimeCompletions). - WithChangedOption(Metadata.ProvideRegexCompletions, language, ProvideRegexCompletions). - WithChangedOption(Metadata.TimeoutInMillisecondsForExtensionMethodImportCompletion, TimeoutInMillisecondsForExtensionMethodImportCompletion); + // note: must pass at least one parameter to avoid calling default ctor: + public static readonly CompletionOptions Default = new(TriggerOnTyping: true); public RecommendationServiceOptions ToRecommendationServiceOptions() => new( FilterOutOfScopeLocals: FilterOutOfScopeLocals, HideAdvancedMembers: HideAdvancedMembers); - public OptionSet ToSet(string language) - => WithChangedOptions(OptionValueSet.Empty, language); - - [ExportSolutionOptionProvider, Shared] - internal sealed class Metadata : IOptionProvider + /// + /// Whether items from unimported namespaces 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 ShouldShowItemsFromUnimportNamspaces() { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Metadata() - { - } - - public ImmutableArray Options { get; } = ImmutableArray.Create( - TypeImportCompletionFeatureFlag, - TargetTypedCompletionFilterFeatureFlag, - UnnamedSymbolCompletionDisabledFeatureFlag, - HideAdvancedMembers, - TriggerOnTyping, - TriggerOnTypingLetters, - EnterKeyBehavior, - SnippetsBehavior, - ShowItemsFromUnimportedNamespaces, - TriggerInArgumentLists, - ProvideRegexCompletions, - ProvideDateAndTimeCompletions); - - // feature flags - - public static readonly Option2 TypeImportCompletionFeatureFlag = new(nameof(CompletionOptions), nameof(TypeImportCompletionFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.TypeImportCompletion")); - - public static readonly Option2 TargetTypedCompletionFilterFeatureFlag = new(nameof(CompletionOptions), nameof(TargetTypedCompletionFilterFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.TargetTypedCompletionFilter")); - - public static readonly Option2 UnnamedSymbolCompletionDisabledFeatureFlag = new(nameof(CompletionOptions), nameof(UnnamedSymbolCompletionDisabledFeatureFlag), defaultValue: false, - new FeatureFlagStorageLocation("Roslyn.UnnamedSymbolCompletionDisabled")); - - // This is serialized by the Visual Studio-specific LanguageSettingsPersister - public static readonly PerLanguageOption2 HideAdvancedMembers = new(nameof(CompletionOptions), nameof(HideAdvancedMembers), defaultValue: false); - - // This is serialized by the Visual Studio-specific LanguageSettingsPersister - public static readonly PerLanguageOption2 TriggerOnTyping = new(nameof(CompletionOptions), nameof(TriggerOnTyping), defaultValue: true); - - public static readonly PerLanguageOption2 TriggerOnTypingLetters = new(nameof(CompletionOptions), nameof(TriggerOnTypingLetters), defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnTypingLetters")); - - public static readonly PerLanguageOption2 TriggerOnDeletion = new(nameof(CompletionOptions), nameof(TriggerOnDeletion), defaultValue: null, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnDeletion")); - - public static readonly PerLanguageOption2 EnterKeyBehavior = - new(nameof(CompletionOptions), nameof(EnterKeyBehavior), defaultValue: EnterKeyRule.Default, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.EnterKeyBehavior")); - - public static readonly PerLanguageOption2 SnippetsBehavior = - new(nameof(CompletionOptions), nameof(SnippetsBehavior), defaultValue: SnippetsRule.Default, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SnippetsBehavior")); - - public static readonly PerLanguageOption2 ShowNameSuggestions = - new(nameof(CompletionOptions), nameof(ShowNameSuggestions), defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowNameSuggestions")); - - //Dev16 options - - // Use tri-value so the default state can be used to turn on the feature with experimentation service. - public static readonly PerLanguageOption2 ShowItemsFromUnimportedNamespaces = - new(nameof(CompletionOptions), nameof(ShowItemsFromUnimportedNamespaces), defaultValue: null, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowItemsFromUnimportedNamespaces")); - - public static readonly PerLanguageOption2 TriggerInArgumentLists = - new(nameof(CompletionOptions), nameof(TriggerInArgumentLists), defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerInArgumentLists")); - - /// - /// Indicates if the completion is trigger by toggle the expander. - /// - public static readonly Option2 IsExpandedCompletion - = new("CompletionServiceOptions", nameof(IsExpandedCompletion), defaultValue: false); - - /// - /// Timeout value used for time-boxing completion of unimported extension methods. - /// Value less than 0 means no timebox; value == 0 means immediate timeout (for testing purpose) - /// - public static readonly Option2 TimeoutInMillisecondsForExtensionMethodImportCompletion - = new("CompletionServiceOptions", nameof(TimeoutInMillisecondsForExtensionMethodImportCompletion), defaultValue: 500); - - // Embedded languages: - - public static PerLanguageOption2 ProvideRegexCompletions = - new( - "RegularExpressionsOptions", - nameof(ProvideRegexCompletions), - defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideRegexCompletions")); - - public static readonly PerLanguageOption2 ProvideDateAndTimeCompletions = - new( - "DateAndTime", - nameof(ProvideDateAndTimeCompletions), - defaultValue: true, - storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideDateAndTimeCompletions")); + // Don't trigger import completion if the option value is "default" and the experiment is disabled for the user. + return ShowItemsFromUnimportedNamespaces ?? TypeImportCompletion; } } } diff --git a/src/Features/Core/Portable/Completion/CompletionOptionsStorage.cs b/src/Features/Core/Portable/Completion/CompletionOptionsStorage.cs new file mode 100644 index 0000000000000..b0b061f239fdb --- /dev/null +++ b/src/Features/Core/Portable/Completion/CompletionOptionsStorage.cs @@ -0,0 +1,99 @@ +// Licensed to the .NET Foundation under one or more agreements. +// 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.Completion +{ + // TODO: Move to EditorFeatures https://github.com/dotnet/roslyn/issues/59184 + internal static class CompletionOptionsStorage + { + public static CompletionOptions GetCompletionOptions(this IGlobalOptionService options, string language) + => new( + TriggerOnTyping: options.GetOption(TriggerOnTyping, language), + TriggerOnTypingLetters: options.GetOption(TriggerOnTypingLetters, language), + TriggerOnDeletion: options.GetOption(TriggerOnDeletion, language), + TriggerInArgumentLists: options.GetOption(TriggerInArgumentLists, language), + EnterKeyBehavior: options.GetOption(EnterKeyBehavior, language), + SnippetsBehavior: options.GetOption(SnippetsBehavior, language), + HideAdvancedMembers: options.GetOption(HideAdvancedMembers, language), + ShowNameSuggestions: options.GetOption(ShowNameSuggestions, language), + ShowItemsFromUnimportedNamespaces: options.GetOption(ShowItemsFromUnimportedNamespaces, language), + UnnamedSymbolCompletionDisabled: options.GetOption(UnnamedSymbolCompletionDisabledFeatureFlag), + TargetTypedCompletionFilter: options.GetOption(TargetTypedCompletionFilterFeatureFlag), + TypeImportCompletion: options.GetOption(TypeImportCompletionFeatureFlag), + ProvideDateAndTimeCompletions: options.GetOption(ProvideDateAndTimeCompletions, language), + ProvideRegexCompletions: options.GetOption(ProvideRegexCompletions, language), + ForceExpandedCompletionIndexCreation: options.GetOption(ForceExpandedCompletionIndexCreation)); + + // feature flags + + public static readonly Option2 TypeImportCompletionFeatureFlag = new(nameof(CompletionOptions), nameof(TypeImportCompletionFeatureFlag), + CompletionOptions.Default.TypeImportCompletion, + new FeatureFlagStorageLocation("Roslyn.TypeImportCompletion")); + + public static readonly Option2 TargetTypedCompletionFilterFeatureFlag = new(nameof(CompletionOptions), nameof(TargetTypedCompletionFilterFeatureFlag), + CompletionOptions.Default.TargetTypedCompletionFilter, + new FeatureFlagStorageLocation("Roslyn.TargetTypedCompletionFilter")); + + public static readonly Option2 UnnamedSymbolCompletionDisabledFeatureFlag = new(nameof(CompletionOptions), nameof(UnnamedSymbolCompletionDisabledFeatureFlag), + 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); + + // 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 TriggerOnTypingLetters = new(nameof(CompletionOptions), nameof(TriggerOnTypingLetters), CompletionOptions.Default.TriggerOnTypingLetters, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnTypingLetters")); + + public static readonly PerLanguageOption2 TriggerOnDeletion = new(nameof(CompletionOptions), nameof(TriggerOnDeletion), CompletionOptions.Default.TriggerOnDeletion, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnDeletion")); + + public static readonly PerLanguageOption2 EnterKeyBehavior = + new(nameof(CompletionOptions), nameof(EnterKeyBehavior), CompletionOptions.Default.EnterKeyBehavior, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.EnterKeyBehavior")); + + public static readonly PerLanguageOption2 SnippetsBehavior = + new(nameof(CompletionOptions), nameof(SnippetsBehavior), CompletionOptions.Default.SnippetsBehavior, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.SnippetsBehavior")); + + public static readonly PerLanguageOption2 ShowNameSuggestions = + new(nameof(CompletionOptions), nameof(ShowNameSuggestions), CompletionOptions.Default.ShowNameSuggestions, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowNameSuggestions")); + + //Dev16 options + + // Use tri-value so the default state can be used to turn on the feature with experimentation service. + public static readonly PerLanguageOption2 ShowItemsFromUnimportedNamespaces = + new(nameof(CompletionOptions), nameof(ShowItemsFromUnimportedNamespaces), CompletionOptions.Default.ShowItemsFromUnimportedNamespaces, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ShowItemsFromUnimportedNamespaces")); + + public static readonly PerLanguageOption2 TriggerInArgumentLists = + new(nameof(CompletionOptions), nameof(TriggerInArgumentLists), CompletionOptions.Default.TriggerInArgumentLists, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerInArgumentLists")); + + // Test-only option + public static readonly Option2 ForceExpandedCompletionIndexCreation + = new(nameof(CompletionOptions), nameof(ForceExpandedCompletionIndexCreation), defaultValue: false); + + // Embedded languages: + + public static PerLanguageOption2 ProvideRegexCompletions = + new( + "RegularExpressionsOptions", + nameof(ProvideRegexCompletions), + CompletionOptions.Default.ProvideRegexCompletions, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideRegexCompletions")); + + public static readonly PerLanguageOption2 ProvideDateAndTimeCompletions = + new( + "DateAndTime", + nameof(ProvideDateAndTimeCompletions), + CompletionOptions.Default.ProvideDateAndTimeCompletions, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ProvideDateAndTimeCompletions")); + } +} diff --git a/src/Features/Core/Portable/Completion/CompletionProvider.cs b/src/Features/Core/Portable/Completion/CompletionProvider.cs index 3d96addd9a459..e23688c70c16f 100644 --- a/src/Features/Core/Portable/Completion/CompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/CompletionProvider.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -45,9 +44,9 @@ 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) -#pragma warning disable RS0030 // Do not use banned APIs - => ShouldTriggerCompletion(text, caretPosition, trigger, options.ToSet(languageServices.Language)); + internal virtual bool ShouldTriggerCompletion(HostLanguageServices 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 /// @@ -56,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); + => ShouldTriggerCompletion(document.Project.LanguageServices, 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.cs b/src/Features/Core/Portable/Completion/CompletionService.cs index 45ad8f8f248e1..f7945247ffcd7 100644 --- a/src/Features/Core/Portable/Completion/CompletionService.cs +++ b/src/Features/Core/Portable/Completion/CompletionService.cs @@ -78,6 +78,7 @@ public virtual bool ShouldTriggerCompletion( /// The position of the caret after the triggering action. /// The potential triggering action. /// Options. + /// Options originating either from external caller of the or set externally to . /// Optional set of roles associated with the editor state. /// /// We pass the project here to retrieve information about the , @@ -91,10 +92,11 @@ internal virtual bool ShouldTriggerCompletion( int caretPosition, CompletionTrigger trigger, CompletionOptions options, + OptionSet passThroughOptions, ImmutableHashSet? roles = null) { Debug.Fail("Backward compat only, should not be called"); - return ShouldTriggerCompletion(text, caretPosition, trigger, roles, options.ToSet(languageServices.Language)); + return ShouldTriggerCompletion(text, caretPosition, trigger, roles, passThroughOptions); } /// @@ -131,23 +133,25 @@ public virtual TextSpan GetDefaultCompletionListSpan(SourceText text, int caretP CancellationToken cancellationToken = default); /// - /// Gets the completions available at the caret position, with additional info indicates - /// whether expander items are available. + /// Gets the completions available at the caret position. /// - /// - /// expandItemsAvailable is true when expanded items are returned or can be provided upon request. - /// - internal virtual async Task<(CompletionList? completionList, bool expandItemsAvailable)> GetCompletionsInternalAsync( + /// The document that completion is occurring within. + /// The position of the caret after the triggering action. + /// The CompletionOptions that override the default options. + /// The triggering action. + /// Optional set of roles associated with the editor state. + /// + internal virtual async Task GetCompletionsAsync( Document document, int caretPosition, CompletionOptions options, + OptionSet passThroughOptions, CompletionTrigger trigger = default, ImmutableHashSet? roles = null, CancellationToken cancellationToken = default) { #pragma warning disable RS0030 // Do not use banned APIs - var completionList = await GetCompletionsAsync(document, caretPosition, trigger, roles, options.ToSet(document.Project.Language), cancellationToken).ConfigureAwait(false); - return (completionList, false); + return await GetCompletionsAsync(document, caretPosition, trigger, roles, passThroughOptions, cancellationToken).ConfigureAwait(false) ?? CompletionList.Empty; #pragma warning restore } @@ -162,7 +166,12 @@ public virtual TextSpan GetDefaultCompletionListSpan(SourceText text, int caretP Document document, CompletionItem item, CancellationToken cancellationToken = default) - => GetDescriptionAsync(document, item, CompletionOptions.From(document.Project), SymbolDescriptionOptions.From(document.Project), cancellationToken); + { + Debug.Fail("For backwards API compat only, should not be called"); + + // Publicly available options do not affect this API. + return GetDescriptionAsync(document, item, CompletionOptions.Default, SymbolDescriptionOptions.Default, cancellationToken); + } /// /// Gets the description of the item. diff --git a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders+ProjectCompletionProvider.cs b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders+ProjectCompletionProvider.cs deleted file mode 100644 index f644610495f94..0000000000000 --- a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders+ProjectCompletionProvider.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 Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.CodeAnalysis.Completion -{ - public abstract partial class CompletionServiceWithProviders - { - private class ProjectCompletionProvider - : AbstractProjectExtensionProvider - { - public ProjectCompletionProvider(AnalyzerReference reference) - : base(reference) - { - } - - protected override bool SupportsLanguage(ExportCompletionProviderAttribute exportAttribute, string language) - { - return exportAttribute.Language == null - || exportAttribute.Language.Length == 0 - || exportAttribute.Language.Contains(language); - } - - protected override bool TryGetExtensionsFromReference(AnalyzerReference reference, out ImmutableArray extensions) - { - // check whether the analyzer reference knows how to return completion providers directly. - if (reference is ICompletionProviderFactory completionProviderFactory) - { - extensions = completionProviderFactory.GetCompletionProviders(); - return true; - } - - extensions = default; - return false; - } - } - } -} diff --git a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.ProviderManager.cs b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.ProviderManager.cs new file mode 100644 index 0000000000000..2fe6bf7ef83d4 --- /dev/null +++ b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.ProviderManager.cs @@ -0,0 +1,286 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.CodeAnalysis; +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; + +namespace Microsoft.CodeAnalysis.Completion +{ + public abstract partial class CompletionServiceWithProviders + { + private sealed class ProviderManager : IEqualityComparer> + { + private readonly object _gate = new(); + private readonly Dictionary _nameToProvider = new(); + private readonly Dictionary, ImmutableArray> _rolesToProviders; + + // Following CWTs are used to cache completion providers from projects' references, + // so we can avoid the slow path unless there's any change to the references. + private readonly ConditionalWeakTable, StrongBox>> _projectCompletionProvidersMap = new(); + private readonly ConditionalWeakTable _analyzerReferenceToCompletionProvidersMap = new(); + + private readonly ConditionalWeakTable.CreateValueCallback _createProjectCompletionProvidersProvider + = new(r => new ProjectCompletionProvider(r)); + + private readonly Func, ImmutableArray> _createRoleProviders; + private readonly Func _getProviderByName; + + private IEnumerable>? _lazyImportedProviders; + private readonly CompletionServiceWithProviders _service; + + public ProviderManager(CompletionServiceWithProviders service) + { + _service = service; + _rolesToProviders = new Dictionary, ImmutableArray>(this); + _createRoleProviders = CreateRoleProviders; + _getProviderByName = GetProviderByName; + } + + public IEnumerable> GetImportedProviders() + { + if (_lazyImportedProviders == null) + { + var language = _service.Language; + var mefExporter = (IMefHostExportProvider)_service._workspace.Services.HostServices; + + var providers = ExtensionOrderer.Order( + mefExporter.GetExports() + .Where(lz => lz.Metadata.Language == language) + ).ToList(); + + Interlocked.CompareExchange(ref _lazyImportedProviders, providers, null); + } + + return _lazyImportedProviders; + } + + public ImmutableArray GetAllProviders(ImmutableHashSet roles) + { + 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 + + return imported.Concat(builtin).ToImmutableArray(); + } + + public ImmutableArray GetProviders(ImmutableHashSet? roles) + { + roles ??= ImmutableHashSet.Empty; + + lock (_gate) + { + return _rolesToProviders.GetOrAdd(roles, _createRoleProviders); + } + } + + public CompletionProvider? GetProvider(CompletionItem item) + { + CompletionProvider? provider = null; + + if (item.ProviderName != null) + { + lock (_gate) + { + provider = _nameToProvider.GetOrAdd(item.ProviderName, _getProviderByName); + } + } + + return provider; + } + + public ConcatImmutableArray GetFilteredProviders( + Project? project, ImmutableHashSet? roles, CompletionTrigger trigger, in CompletionOptions options) + { + // We need to call `GetProviders` from the service since it could be overridden by its subclasses. + var allCompletionProviders = FilterProviders(_service.GetProviders(roles, trigger), trigger, options); + var projectCompletionProviders = FilterProviders(GetProjectCompletionProviders(project), trigger, options); + return allCompletionProviders.ConcatFast(projectCompletionProviders); + } + + private ImmutableArray GetProjectCompletionProviders(Project? project) + { + if (project is null) + { + return ImmutableArray.Empty; + } + + if (project is null || project.Solution.Workspace.Kind == WorkspaceKind.Interactive) + { + // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict completions in Interactive + return ImmutableArray.Empty; + } + + if (_projectCompletionProvidersMap.TryGetValue(project.AnalyzerReferences, out var completionProviders)) + { + return completionProviders.Value; + } + + return GetProjectCompletionProvidersSlow(project); + + // Local functions + ImmutableArray GetProjectCompletionProvidersSlow(Project project) + { + return _projectCompletionProvidersMap.GetValue(project.AnalyzerReferences, pId => new(ComputeProjectCompletionProviders(project))).Value; + } + + ImmutableArray ComputeProjectCompletionProviders(Project project) + { + using var _ = ArrayBuilder.GetInstance(out var builder); + foreach (var reference in project.AnalyzerReferences) + { + var projectCompletionProvider = _analyzerReferenceToCompletionProvidersMap.GetValue(reference, _createProjectCompletionProvidersProvider); + foreach (var completionProvider in projectCompletionProvider.GetExtensions(project.Language)) + { + builder.Add(completionProvider); + } + } + + return builder.ToImmutable(); + } + } + + private ImmutableArray FilterProviders( + ImmutableArray providers, + CompletionTrigger trigger, + in CompletionOptions options) + { + providers = options.ExpandedCompletionBehavior switch + { + ExpandedCompletionMode.NonExpandedItemsOnly => providers.WhereAsArray(p => !p.IsExpandItemProvider), + ExpandedCompletionMode.ExpandedItemsOnly => providers.WhereAsArray(p => p.IsExpandItemProvider), + _ => providers, + }; + + // If the caller passed along specific options that affect snippets, + // then defer to those. Otherwise if the caller just wants the default + // behavior, then get the snippets behavior from our own rules. + var snippetsRule = options.SnippetsBehavior != SnippetsRule.Default + ? options.SnippetsBehavior + : _service.GetRules(options).SnippetsRule; + + if (snippetsRule is SnippetsRule.Default or + SnippetsRule.NeverInclude) + { + return providers.Where(p => !p.IsSnippetProvider).ToImmutableArray(); + } + else if (snippetsRule == SnippetsRule.AlwaysInclude) + { + return providers; + } + else if (snippetsRule == SnippetsRule.IncludeAfterTypingIdentifierQuestionTab) + { + if (trigger.Kind == CompletionTriggerKind.Snippets) + { + return providers.Where(p => p.IsSnippetProvider).ToImmutableArray(); + } + else + { + return providers.Where(p => !p.IsSnippetProvider).ToImmutableArray(); + } + } + + 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) + { + return true; + } + + if (x == null || y == null || x.Count != y.Count) + { + return false; + } + + foreach (var v in x) + { + if (!y.Contains(v)) + { + return false; + } + } + + return true; + } + + int IEqualityComparer>.GetHashCode([DisallowNull] ImmutableHashSet obj) + { + var hash = 0; + foreach (var o in obj) + { + hash += o.GetHashCode(); + } + + return hash; + } + + private sealed class ProjectCompletionProvider + : AbstractProjectExtensionProvider + { + public ProjectCompletionProvider(AnalyzerReference reference) + : base(reference) + { + } + + protected override bool SupportsLanguage(ExportCompletionProviderAttribute exportAttribute, string language) + { + return exportAttribute.Language == null + || exportAttribute.Language.Length == 0 + || exportAttribute.Language.Contains(language); + } + + protected override bool TryGetExtensionsFromReference(AnalyzerReference reference, out ImmutableArray extensions) + { + // check whether the analyzer reference knows how to return completion providers directly. + if (reference is ICompletionProviderFactory completionProviderFactory) + { + extensions = completionProviderFactory.GetCompletionProviders(); + return true; + } + + extensions = default; + return false; + } + } + } + } +} diff --git a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs index 83b6bd755e1ca..45496d108fc91 100644 --- a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs +++ b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs @@ -6,21 +6,16 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Completion.Providers; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -29,26 +24,10 @@ namespace Microsoft.CodeAnalysis.Completion /// /// A subtype of that aggregates completions from one or more s. /// - public abstract partial class CompletionServiceWithProviders : CompletionService, IEqualityComparer> + public abstract partial class CompletionServiceWithProviders : CompletionService { - private readonly object _gate = new(); - - private readonly ConditionalWeakTable, StrongBox>> _projectCompletionProvidersMap - = new(); - - private readonly ConditionalWeakTable _analyzerReferenceToCompletionProvidersMap - = new(); - private readonly ConditionalWeakTable.CreateValueCallback _createProjectCompletionProvidersProvider - = new(r => new ProjectCompletionProvider(r)); - - private readonly Dictionary _nameToProvider = new(); - private readonly Dictionary, ImmutableArray> _rolesToProviders; - private readonly Func, ImmutableArray> _createRoleProviders; - private readonly Func _getProviderByName; - private readonly Workspace _workspace; - - private IEnumerable>? _lazyImportedProviders; + private readonly ProviderManager _providerManager; /// /// Test-only switch. @@ -58,16 +37,19 @@ private readonly ConditionalWeakTable, ImmutableArray>(this); - _createRoleProviders = CreateRoleProviders; - _getProviderByName = GetProviderByName; + _providerManager = new(this); } /// /// Backward compatibility only. /// public sealed override CompletionRules GetRules() - => GetRules(CompletionOptions.From(_workspace.CurrentSolution.Options, Language)); + { + Debug.Fail("For backwards API compat only, should not be called"); + + // Publicly available options do not affect this API. + return GetRules(CompletionOptions.Default); + } /// /// Returns the providers always available to the service. @@ -78,194 +60,20 @@ protected virtual ImmutableArray GetBuiltInProviders() => ImmutableArray.Empty; internal IEnumerable> GetImportedProviders() - { - if (_lazyImportedProviders == null) - { - var language = Language; - var mefExporter = (IMefHostExportProvider)_workspace.Services.HostServices; - - var providers = ExtensionOrderer.Order( - mefExporter.GetExports() - .Where(lz => lz.Metadata.Language == language) - ).ToList(); - - Interlocked.CompareExchange(ref _lazyImportedProviders, providers, null); - } - - return _lazyImportedProviders; - } - - private ImmutableArray CreateRoleProviders(ImmutableHashSet roles) - { - var providers = GetAllProviders(roles); - - foreach (var provider in providers) - { - _nameToProvider[provider.Name] = provider; - } - - return providers; - } - - private ImmutableArray GetAllProviders(ImmutableHashSet roles) - { - 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 = GetBuiltInProviders(); -#pragma warning restore 0618 - - return imported.Concat(builtin).ToImmutableArray(); - } + => _providerManager.GetImportedProviders(); protected ImmutableArray GetProviders(ImmutableHashSet? roles) - { - roles ??= ImmutableHashSet.Empty; - - lock (_gate) - { - return _rolesToProviders.GetOrAdd(roles, _createRoleProviders); - } - } - - private ConcatImmutableArray GetFilteredProviders( - Project? project, ImmutableHashSet? roles, CompletionTrigger trigger, in CompletionOptions options) - { - var allCompletionProviders = FilterProviders(GetProviders(roles, trigger), trigger, options); - var projectCompletionProviders = FilterProviders(GetProjectCompletionProviders(project), trigger, options); - return allCompletionProviders.ConcatFast(projectCompletionProviders); - } - - protected virtual ImmutableArray GetProviders( - ImmutableHashSet? roles, CompletionTrigger trigger) - { - return GetProviders(roles); - } + => _providerManager.GetProviders(roles); - private ImmutableArray GetProjectCompletionProviders(Project? project) - { - if (project is null) - { - return ImmutableArray.Empty; - } - - if (project is null || project.Solution.Workspace.Kind == WorkspaceKind.Interactive) - { - // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict completions in Interactive - return ImmutableArray.Empty; - } - - if (_projectCompletionProvidersMap.TryGetValue(project.AnalyzerReferences, out var completionProviders)) - { - return completionProviders.Value; - } - - return GetProjectCompletionProvidersSlow(project); - - // Local functions - ImmutableArray GetProjectCompletionProvidersSlow(Project project) - { - return _projectCompletionProvidersMap.GetValue(project.AnalyzerReferences, pId => new StrongBox>(ComputeProjectCompletionProviders(project))).Value; - } - - ImmutableArray ComputeProjectCompletionProviders(Project project) - { - using var _ = ArrayBuilder.GetInstance(out var builder); - foreach (var reference in project.AnalyzerReferences) - { - var projectCompletionProvider = _analyzerReferenceToCompletionProvidersMap.GetValue(reference, _createProjectCompletionProvidersProvider); - foreach (var completionProvider in projectCompletionProvider.GetExtensions(project.Language)) - { - builder.Add(completionProvider); - } - } - - return builder.ToImmutable(); - } - } - - private ImmutableArray FilterProviders( - ImmutableArray providers, - CompletionTrigger trigger, - in CompletionOptions options) - { - if (options.IsExpandedCompletion) - { - providers = providers.WhereAsArray(p => p.IsExpandItemProvider); - } - - // If the caller passed along specific options that affect snippets, - // then defer to those. Otherwise if the caller just wants the default - // behavior, then get the snippets behavior from our own rules. - var snippetsRule = options.SnippetsBehavior != SnippetsRule.Default - ? options.SnippetsBehavior - : GetRules(options).SnippetsRule; - - if (snippetsRule is SnippetsRule.Default or - SnippetsRule.NeverInclude) - { - return providers.Where(p => !p.IsSnippetProvider).ToImmutableArray(); - } - else if (snippetsRule == SnippetsRule.AlwaysInclude) - { - return providers; - } - else if (snippetsRule == SnippetsRule.IncludeAfterTypingIdentifierQuestionTab) - { - if (trigger.Kind == CompletionTriggerKind.Snippets) - { - return providers.Where(p => p.IsSnippetProvider).ToImmutableArray(); - } - else - { - return providers.Where(p => !p.IsSnippetProvider).ToImmutableArray(); - } - } - - return ImmutableArray.Empty; - } + protected virtual ImmutableArray GetProviders(ImmutableHashSet? roles, CompletionTrigger trigger) + => GetProviders(roles); protected internal CompletionProvider? GetProvider(CompletionItem item) - { - CompletionProvider? provider = null; - - if (item.ProviderName != null) - { - lock (_gate) - { - provider = _nameToProvider.GetOrAdd(item.ProviderName, _getProviderByName); - } - } - - return provider; - } - - private CompletionProvider? GetProviderByName(string providerName) - { - var providers = GetAllProviders(roles: ImmutableHashSet.Empty); - return providers.FirstOrDefault(p => p.Name == providerName); - } - - public override async Task GetCompletionsAsync( - Document document, - int caretPosition, - CompletionTrigger trigger, - ImmutableHashSet? roles, - OptionSet? options, - CancellationToken cancellationToken) - { - var completionOptions = CompletionOptions.From(options ?? document.Project.Solution.Options, document.Project.Language); - var (completionList, _) = await GetCompletionsWithAvailabilityOfExpandedItemsAsync(document, caretPosition, trigger, roles, completionOptions, cancellationToken).ConfigureAwait(false); - return completionList; - } + => _providerManager.GetProvider(item); /// /// Returns a document with frozen partial semantic unless we already have a complete compilation available. - /// Getting full semantic could be costly in certains scenarios and would cause significant delay in completion. + /// Getting full semantic could be costly in certain scenarios and would cause significant delay in completion. /// In most cases we'd still end up with complete document, but we'd consider it an acceptable trade-off even when /// we get into this transient state. /// @@ -279,12 +87,28 @@ private ImmutableArray FilterProviders( return await document.GetPartialSemanticModelAsync(cancellationToken).ConfigureAwait(false); } - private protected async Task<(CompletionList? completionList, bool expandItemsAvailable)> GetCompletionsWithAvailabilityOfExpandedItemsAsync( + public override async Task GetCompletionsAsync( Document document, int caretPosition, CompletionTrigger trigger, ImmutableHashSet? roles, + OptionSet? options, + CancellationToken cancellationToken) + { + // Publicly available options do not affect this API. + var completionOptions = CompletionOptions.Default; + var passThroughOptions = options ?? document.Project.Solution.Options; + + return await GetCompletionsWithAvailabilityOfExpandedItemsAsync(document, caretPosition, completionOptions, passThroughOptions, trigger, roles, cancellationToken).ConfigureAwait(false); + } + + private protected async Task GetCompletionsWithAvailabilityOfExpandedItemsAsync( + Document document, + int caretPosition, CompletionOptions options, + OptionSet passThroughOptions, + CompletionTrigger trigger, + ImmutableHashSet? roles, CancellationToken cancellationToken) { // We don't need SemanticModel here, just want to make sure it won't get GC'd before CompletionProviders are able to get it. @@ -293,30 +117,7 @@ private ImmutableArray FilterProviders( var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var defaultItemSpan = GetDefaultCompletionListSpan(text, caretPosition); - var providers = GetFilteredProviders(document.Project, roles, trigger, options); - - var completionProviderToIndex = GetCompletionProviderToIndex(providers); - - var triggeredProviders = ImmutableArray.Empty; - switch (trigger.Kind) - { - case CompletionTriggerKind.Insertion: - case CompletionTriggerKind.Deletion: - if (ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, text, caretPosition, trigger, options, roles)) - { - triggeredProviders = providers.Where(p => p.ShouldTriggerCompletion(document.Project.LanguageServices, text, caretPosition, trigger, options)).ToImmutableArrayOrEmpty(); - Debug.Assert(ValidatePossibleTriggerCharacterSet(trigger.Kind, triggeredProviders, document, text, caretPosition, options)); - if (triggeredProviders.Length == 0) - { - triggeredProviders = providers.ToImmutableArray(); - } - } - - break; - default: - triggeredProviders = providers.ToImmutableArray(); - break; - } + var providers = _providerManager.GetFilteredProviders(document.Project, roles, trigger, options); // Phase 1: Completion Providers decide if they are triggered based on textual analysis // Phase 2: Completion Providers use syntax to confirm they are triggered, or decide they are not actually triggered and should become an augmenting provider @@ -324,50 +125,25 @@ private ImmutableArray FilterProviders( // Phase 4: If any items were provided, all augmenting providers are asked for items // This allows a provider to be textually triggered but later decide to be an augmenting provider based on deeper syntactic analysis. - var additionalAugmentingProviders = new List(); - if (trigger.Kind == CompletionTriggerKind.Insertion) - { - foreach (var provider in triggeredProviders) - { - if (!await provider.IsSyntacticTriggerCharacterAsync(document, caretPosition, trigger, options, cancellationToken).ConfigureAwait(false)) - { - additionalAugmentingProviders.Add(provider); - } - } - } + var triggeredProviders = GetTriggeredProviders(document, providers, caretPosition, options, trigger, roles, text); + var additionalAugmentingProviders = await GetAugmentingProviders(document, triggeredProviders, caretPosition, trigger, options, cancellationToken).ConfigureAwait(false); triggeredProviders = triggeredProviders.Except(additionalAugmentingProviders).ToImmutableArray(); // Now, ask all the triggered providers, in parallel, to populate a completion context. // Note: we keep any context with items *or* with a suggested item. - var (triggeredCompletionContexts, expandItemsAvailableFromTriggeredProviders) = await ComputeNonEmptyCompletionContextsAsync( - document, caretPosition, trigger, options, - defaultItemSpan, triggeredProviders, - cancellationToken).ConfigureAwait(false); - - // If we didn't even get any back with items, then there's nothing to do. - // i.e. if only got items back that had only suggestion items, then we don't - // want to show any completion. - if (!triggeredCompletionContexts.Any(cc => cc.Items.Count > 0)) - { - return (null, expandItemsAvailableFromTriggeredProviders); - } + var triggeredContexts = await ComputeNonEmptyCompletionContextsAsync( + document, caretPosition, trigger, options, defaultItemSpan, triggeredProviders, cancellationToken).ConfigureAwait(false); - // All the contexts should be non-empty or have a suggestion item. - Debug.Assert(triggeredCompletionContexts.All(HasAnyItems)); + // Nothing to do if we didn't even get any regular items back (i.e. 0 items or suggestion item only.) + if (!triggeredContexts.Any(cc => cc.Items.Count > 0)) + return CompletionList.Empty; // See if there were completion contexts provided that were exclusive. If so, then // that's all we'll return. - var exclusiveContexts = triggeredCompletionContexts.Where(t => t.IsExclusive); - - if (exclusiveContexts.Any()) - { - return (MergeAndPruneCompletionLists(exclusiveContexts, defaultItemSpan, options, isExclusive: true), - expandItemsAvailableFromTriggeredProviders); - } - - // Shouldn't be any exclusive completion contexts at this point. - Debug.Assert(triggeredCompletionContexts.All(cc => !cc.IsExclusive)); + var exclusiveContexts = triggeredContexts.Where(t => t.IsExclusive).ToImmutableArray(); + if (!exclusiveContexts.IsEmpty) + return MergeAndPruneCompletionLists(exclusiveContexts, defaultItemSpan, options, isExclusive: true); // Great! We had some items. Now we want to see if any of the other providers // would like to augment the completion list. For example, we might trigger @@ -375,23 +151,96 @@ private ImmutableArray FilterProviders( // we'll want to augment the list with all the regular symbol completion items. var augmentingProviders = providers.Except(triggeredProviders).ToImmutableArray(); - var (augmentingCompletionContexts, expandItemsAvailableFromAugmentingProviders) = await ComputeNonEmptyCompletionContextsAsync( - document, caretPosition, trigger, options, defaultItemSpan, - augmentingProviders, cancellationToken).ConfigureAwait(false); + var augmentingContexts = await ComputeNonEmptyCompletionContextsAsync( + document, caretPosition, trigger, options, defaultItemSpan, augmentingProviders, cancellationToken).ConfigureAwait(false); GC.KeepAlive(semanticModel); - var allContexts = triggeredCompletionContexts.Concat(augmentingCompletionContexts); - Debug.Assert(allContexts.Length > 0); - // Providers are ordered, but we processed them in our own order. Ensure that the // groups are properly ordered based on the original providers. - allContexts = allContexts.Sort((p1, p2) => completionProviderToIndex[p1.Provider] - completionProviderToIndex[p2.Provider]); + var completionProviderToIndex = GetCompletionProviderToIndex(providers); + var allContexts = triggeredContexts.Concat(augmentingContexts) + .Sort((p1, p2) => completionProviderToIndex[p1.Provider] - completionProviderToIndex[p2.Provider]); + + return MergeAndPruneCompletionLists(allContexts, defaultItemSpan, options, isExclusive: false); + + ImmutableArray GetTriggeredProviders( + Document document, ConcatImmutableArray providers, int caretPosition, CompletionOptions options, CompletionTrigger trigger, ImmutableHashSet? roles, SourceText text) + { + switch (trigger.Kind) + { + case CompletionTriggerKind.Insertion: + case CompletionTriggerKind.Deletion: + + if (ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, text, caretPosition, trigger, options, passThroughOptions, roles)) + { + var triggeredProviders = providers.Where(p => p.ShouldTriggerCompletion(document.Project.LanguageServices, text, caretPosition, trigger, options, passThroughOptions)).ToImmutableArrayOrEmpty(); + + Debug.Assert(ValidatePossibleTriggerCharacterSet(trigger.Kind, triggeredProviders, document, text, caretPosition, options)); + return triggeredProviders.IsEmpty ? providers.ToImmutableArray() : triggeredProviders; + } + + return ImmutableArray.Empty; + + default: + return providers.ToImmutableArray(); + } + } + + static async Task> GetAugmentingProviders( + Document document, ImmutableArray triggeredProviders, int caretPosition, CompletionTrigger trigger, CompletionOptions options, CancellationToken cancellationToken) + { + var additionalAugmentingProviders = ArrayBuilder.GetInstance(triggeredProviders.Length); + if (trigger.Kind == CompletionTriggerKind.Insertion) + { + foreach (var provider in triggeredProviders) + { + if (!await provider.IsSyntacticTriggerCharacterAsync(document, caretPosition, trigger, options, cancellationToken).ConfigureAwait(false)) + { + additionalAugmentingProviders.Add(provider); + } + } + } + + return additionalAugmentingProviders.ToImmutableAndFree(); + } + } + + /// + /// Backward compatibility only. + /// + public sealed override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, ImmutableHashSet? roles = null, OptionSet? options = null) + { + var document = text.GetOpenDocumentInCurrentContextWithChanges(); + var languageServices = document?.Project.LanguageServices ?? _workspace.Services.GetLanguageServices(Language); + + // Publicly available options do not affect this API. + var completionOptions = CompletionOptions.Default; + var passThroughOptions = options ?? document?.Project.Solution.Options ?? OptionValueSet.Empty; + + return ShouldTriggerCompletion(document?.Project, languageServices, text, caretPosition, trigger, completionOptions, passThroughOptions, roles); + } + + internal sealed override bool ShouldTriggerCompletion( + Project? project, HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions, ImmutableHashSet? roles = null) + { + if (!options.TriggerOnTyping) + { + return false; + } + + if (trigger.Kind == CompletionTriggerKind.Deletion && SupportsTriggerOnDeletion(options)) + { + return char.IsLetterOrDigit(trigger.Character) || trigger.Character == '.'; + } - return (MergeAndPruneCompletionLists(allContexts, defaultItemSpan, options, isExclusive: false), - (expandItemsAvailableFromTriggeredProviders || expandItemsAvailableFromAugmentingProviders)); + var providers = _providerManager.GetFilteredProviders(project, roles, trigger, options); + return providers.Any(p => p.ShouldTriggerCompletion(languageServices, text, caretPosition, trigger, options, passThroughOptions)); } + internal virtual bool SupportsTriggerOnDeletion(CompletionOptions options) + => options.TriggerOnDeletion == true; + private static bool ValidatePossibleTriggerCharacterSet(CompletionTriggerKind completionTriggerKind, IEnumerable triggeredProviders, Document document, SourceText text, int caretPosition, in CompletionOptions options) { @@ -434,7 +283,7 @@ private static bool ValidatePossibleTriggerCharacterSet(CompletionTriggerKind co private static bool HasAnyItems(CompletionContext cc) => cc.Items.Count > 0 || cc.SuggestionModeItem != null; - private async Task<(ImmutableArray, bool)> ComputeNonEmptyCompletionContextsAsync( + private static async Task> ComputeNonEmptyCompletionContextsAsync( Document document, int caretPosition, CompletionTrigger trigger, CompletionOptions options, TextSpan defaultItemSpan, ImmutableArray providers, @@ -449,13 +298,11 @@ private static bool HasAnyItems(CompletionContext cc) } var completionContexts = await Task.WhenAll(completionContextTasks).ConfigureAwait(false); - var nonEmptyContexts = completionContexts.Where(HasAnyItems).ToImmutableArray(); - var shouldShowExpander = completionContexts.Any(context => context.ExpandItemsAvailable); - return (nonEmptyContexts, shouldShowExpander); + return completionContexts.Where(HasAnyItems).ToImmutableArray(); } private CompletionList MergeAndPruneCompletionLists( - IEnumerable completionContexts, + ImmutableArray completionContexts, TextSpan defaultSpan, in CompletionOptions options, bool isExclusive) @@ -469,8 +316,6 @@ private CompletionList MergeAndPruneCompletionLists( foreach (var context in completionContexts) { - Debug.Assert(context != null); - foreach (var item in context.Items) { Debug.Assert(item != null); @@ -531,22 +376,16 @@ private static Dictionary GetCompletionProviderToIndex( return result; } - private async Task GetContextAsync( + private static async Task GetContextAsync( CompletionProvider provider, Document document, int position, CompletionTrigger triggerInfo, CompletionOptions options, - TextSpan? defaultSpan, + TextSpan defaultSpan, CancellationToken cancellationToken) { - if (defaultSpan == null) - { - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - defaultSpan = GetDefaultCompletionListSpan(text, position); - } - - var context = new CompletionContext(provider, document, position, defaultSpan.Value, triggerInfo, options, cancellationToken); + var context = new CompletionContext(provider, document, position, defaultSpan, triggerInfo, options, cancellationToken); await provider.ProvideCompletionsAsync(context).ConfigureAwait(false); return context; } @@ -564,37 +403,6 @@ private async Task GetContextAsync( return description; } - /// - /// Backward compatibility only. - /// - public sealed override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, ImmutableHashSet? roles = null, OptionSet? options = null) - { - var document = text.GetOpenDocumentInCurrentContextWithChanges(); - var languageServices = document?.Project.LanguageServices ?? _workspace.Services.GetLanguageServices(Language); - var completionOptions = CompletionOptions.From(options ?? document?.Project.Solution.Options ?? _workspace.CurrentSolution.Options, document?.Project.Language ?? Language); - return ShouldTriggerCompletion(document?.Project, languageServices, text, caretPosition, trigger, completionOptions, roles); - } - - internal sealed override bool ShouldTriggerCompletion( - Project? project, HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, ImmutableHashSet? roles = null) - { - if (!options.TriggerOnTyping) - { - return false; - } - - if (trigger.Kind == CompletionTriggerKind.Deletion && SupportsTriggerOnDeletion(options)) - { - return char.IsLetterOrDigit(trigger.Character) || trigger.Character == '.'; - } - - var providers = GetFilteredProviders(project, roles, trigger, options); - return providers.Any(p => p.ShouldTriggerCompletion(languageServices, text, caretPosition, trigger, options)); - } - - internal virtual bool SupportsTriggerOnDeletion(CompletionOptions options) - => options.TriggerOnDeletion == true; - public override async Task GetChangeAsync( Document document, CompletionItem item, char? commitKey, CancellationToken cancellationToken) { @@ -613,40 +421,6 @@ public override async Task GetChangeAsync( } } - bool IEqualityComparer>.Equals([AllowNull] ImmutableHashSet x, [AllowNull] ImmutableHashSet y) - { - if (x == y) - { - return true; - } - - if (x == null || y == null || x.Count != y.Count) - { - return false; - } - - foreach (var v in x) - { - if (!y.Contains(v)) - { - return false; - } - } - - return true; - } - - int IEqualityComparer>.GetHashCode([DisallowNull] ImmutableHashSet obj) - { - var hash = 0; - foreach (var o in obj) - { - hash += o.GetHashCode(); - } - - return hash; - } - private class DisplayNameToItemsMap : IEnumerable, IDisposable { // We might need to handle large amount of items with import completion enabled, @@ -752,9 +526,9 @@ public TestAccessor(CompletionServiceWithProviders completionServiceWithProvider => _completionServiceWithProviders = completionServiceWithProviders; internal ImmutableArray GetAllProviders(ImmutableHashSet roles) - => _completionServiceWithProviders.GetAllProviders(roles); + => _completionServiceWithProviders._providerManager.GetAllProviders(roles); - internal Task GetContextAsync( + internal async Task GetContextAsync( CompletionProvider provider, Document document, int position, @@ -762,14 +536,17 @@ internal Task GetContextAsync( CompletionOptions options, CancellationToken cancellationToken) { - return _completionServiceWithProviders.GetContextAsync( + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var defaultItemSpan = _completionServiceWithProviders.GetDefaultCompletionListSpan(text, position); + + return await CompletionServiceWithProviders.GetContextAsync( provider, document, position, triggerInfo, options, - defaultSpan: null, - cancellationToken); + defaultItemSpan, + cancellationToken).ConfigureAwait(false); } public void SuppressPartialSemantics() diff --git a/src/Compilers/CSharp/Portable/BoundTree/IBoundSwitchStatement.cs b/src/Features/Core/Portable/Completion/ExpandedCompletionMode.cs similarity index 51% rename from src/Compilers/CSharp/Portable/BoundTree/IBoundSwitchStatement.cs rename to src/Features/Core/Portable/Completion/ExpandedCompletionMode.cs index 24aab819949df..56a7abbd701a0 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/IBoundSwitchStatement.cs +++ b/src/Features/Core/Portable/Completion/ExpandedCompletionMode.cs @@ -2,13 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Immutable; - -namespace Microsoft.CodeAnalysis.CSharp +namespace Microsoft.CodeAnalysis.Completion { - internal interface IBoundSwitchStatement + internal enum ExpandedCompletionMode { - BoundNode Value { get; } - ImmutableArray Cases { get; } + NonExpandedItemsOnly, + ExpandedItemsOnly, + AllItems } } diff --git a/src/Features/Core/Portable/Completion/Log/CompletionProvidersLogger.cs b/src/Features/Core/Portable/Completion/Log/CompletionProvidersLogger.cs index 7c54b57554ed7..56bb70cbe643a 100644 --- a/src/Features/Core/Portable/Completion/Log/CompletionProvidersLogger.cs +++ b/src/Features/Core/Portable/Completion/Log/CompletionProvidersLogger.cs @@ -16,7 +16,6 @@ internal static class CompletionProvidersLogger internal enum ActionInfo { TypeImportCompletionTicks, - TypeImportCompletionExpanderTicks, // time to complete the request when expander is used (i.e. no timeout or partial results) TypeImportCompletionItemCount, TypeImportCompletionReferenceCount, TypeImportCompletionCacheMissCount, @@ -25,30 +24,21 @@ internal enum ActionInfo TargetTypeCompletionTicks, ExtensionMethodCompletionTicks, - ExtensionMethodCompletionExpanderTicks, // time to complete the request when expander is used (i.e. no timeout or partial results) ExtensionMethodCompletionMethodsProvided, ExtensionMethodCompletionGetSymbolsTicks, ExtensionMethodCompletionCreateItemsTicks, ExtensionMethodCompletionRemoteTicks, CommitsOfExtensionMethodImportCompletionItem, ExtensionMethodCompletionPartialResultCount, - ExtensionMethodCompletionTimeoutCount, CommitUsingSemicolonToAddParenthesis, CommitUsingDotToAddParenthesis } - internal static void LogTypeImportCompletionTicksDataPoint(int count, bool isExpanded) + internal static void LogTypeImportCompletionTicksDataPoint(int count) { - if (isExpanded) - { - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.TypeImportCompletionExpanderTicks, count); - } - else - { - s_histogramLogAggregator.IncreaseCount((int)ActionInfo.TypeImportCompletionTicks, count); - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.TypeImportCompletionTicks, count); - } + s_histogramLogAggregator.IncreaseCount((int)ActionInfo.TypeImportCompletionTicks, count); + s_statisticLogAggregator.AddDataPoint((int)ActionInfo.TypeImportCompletionTicks, count); } internal static void LogTypeImportCompletionItemCountDataPoint(int count) => @@ -69,17 +59,10 @@ internal static void LogTargetTypeCompletionTicksDataPoint(int count) s_histogramLogAggregator.IncreaseCount((int)ActionInfo.TargetTypeCompletionTicks, count); } - internal static void LogExtensionMethodCompletionTicksDataPoint(int total, int getSymbols, int createItems, bool isExpanded, bool isRemote) + internal static void LogExtensionMethodCompletionTicksDataPoint(int total, int getSymbols, int createItems, bool isRemote) { - if (isExpanded) - { - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionExpanderTicks, total); - } - else - { - s_histogramLogAggregator.IncreaseCount((int)ActionInfo.ExtensionMethodCompletionTicks, total); - s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionTicks, total); - } + s_histogramLogAggregator.IncreaseCount((int)ActionInfo.ExtensionMethodCompletionTicks, total); + s_statisticLogAggregator.AddDataPoint((int)ActionInfo.ExtensionMethodCompletionTicks, total); if (isRemote) { @@ -99,9 +82,6 @@ internal static void LogCommitOfExtensionMethodImportCompletionItem() => internal static void LogExtensionMethodCompletionPartialResultCount() => s_logAggregator.IncreaseCount((int)ActionInfo.ExtensionMethodCompletionPartialResultCount); - internal static void LogExtensionMethodCompletionTimeoutCount() => - s_logAggregator.IncreaseCount((int)ActionInfo.ExtensionMethodCompletionTimeoutCount); - internal static void LogCommitUsingSemicolonToAddParenthesis() => s_logAggregator.IncreaseCount((int)ActionInfo.CommitUsingSemicolonToAddParenthesis); diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs index 80728afd365f1..0b9a94bc5bb24 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractAggregateEmbeddedLanguageCompletionProvider.cs @@ -71,7 +71,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) + internal sealed override bool ShouldTriggerCompletion(HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CompletionOptions options, OptionSet passThroughOptions) { foreach (var language in GetLanguageProviders(languageServices)) { @@ -107,17 +107,17 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) } public override Task GetChangeAsync(Document document, CompletionItem item, char? commitKey, CancellationToken cancellationToken) - => GetLanguage(item).CompletionProvider.GetChangeAsync(document, item, commitKey, cancellationToken); + => GetLanguage(item).CompletionProvider!.GetChangeAsync(document, item, commitKey, cancellationToken); internal override Task GetDescriptionAsync(Document document, CompletionItem item, CompletionOptions options, SymbolDescriptionOptions displayOptions, CancellationToken cancellationToken) - => GetLanguage(item).CompletionProvider.GetDescriptionAsync(document, item, cancellationToken); + => GetLanguage(item).CompletionProvider!.GetDescriptionAsync(document, item, cancellationToken); private IEmbeddedLanguageFeatures GetLanguage(CompletionItem item) { if (_languageProviders.IsDefault) throw ExceptionUtilities.Unreachable; - return (IEmbeddedLanguageFeatures)_languageProviders.Single(lang => (lang as IEmbeddedLanguageFeatures)?.CompletionProvider.Name == item.Properties[EmbeddedProviderName]); + return (IEmbeddedLanguageFeatures)_languageProviders.Single(lang => (lang as IEmbeddedLanguageFeatures)?.CompletionProvider?.Name == item.Properties[EmbeddedProviderName]); } } } diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractContextVariableArgumentProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractContextVariableArgumentProvider.cs index a1c6a3818f6d8..91a7bdd9e6fea 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractContextVariableArgumentProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractContextVariableArgumentProvider.cs @@ -2,7 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Completion @@ -12,28 +15,151 @@ namespace Microsoft.CodeAnalysis.Completion /// internal abstract class AbstractContextVariableArgumentProvider : ArgumentProvider { - public override Task ProvideArgumentAsync(ArgumentContext context) + protected abstract string ThisOrMeKeyword { get; } + + protected abstract bool IsInstanceContext(SyntaxTree syntaxTree, SyntaxToken targetToken, SemanticModel semanticModel, CancellationToken cancellationToken); + + public override async Task ProvideArgumentAsync(ArgumentContext context) { if (context.PreviousValue is not null) { // This argument provider does not attempt to replace arguments already in code. - return Task.CompletedTask; + return; } - var symbols = context.SemanticModel.LookupSymbols(context.Position, name: context.Parameter.Name); + var requireExactType = context.Parameter.Type.IsSpecialType() + || context.Parameter.RefKind != RefKind.None; + var symbols = context.SemanticModel.LookupSymbols(context.Position); + + // First try to find a local variable + ISymbol? bestSymbol = null; + string? bestSymbolName = null; + CommonConversion bestConversion = default; foreach (var symbol in symbols) { - // Currently we check for an exact type match before using a variable from context. As we hone the - // default argument provider heuristics, we may alter the definition of "in scope" as well as the type - // and name check(s) that occur. - if (SymbolEqualityComparer.Default.Equals(context.Parameter.Type, symbol.GetSymbolType())) + ISymbol candidate; + if (symbol.IsKind(SymbolKind.Parameter, out IParameterSymbol? parameter)) + candidate = parameter; + else if (symbol.IsKind(SymbolKind.Local, out ILocalSymbol? local)) + candidate = local; + else + continue; + + CheckCandidate(candidate); + } + + if (bestSymbol is not null) + { + context.DefaultValue = bestSymbolName; + return; + } + + // Next try fields and properties of the current type + foreach (var symbol in symbols) + { + ISymbol candidate; + if (symbol.IsKind(SymbolKind.Field, out IFieldSymbol? field)) + candidate = field; + else if (symbol.IsKind(SymbolKind.Property, out IPropertySymbol? property)) + candidate = property; + else + continue; + + // Require a name match for primitive types + if (candidate.GetSymbolType().IsSpecialType() + && !string.Equals(candidate.Name, context.Parameter.Name, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + CheckCandidate(candidate); + } + + if (bestSymbol is not null) + { + context.DefaultValue = bestSymbolName; + return; + } + + // Finally, if the invocation occurs in an instance context, check the current type ('this' or 'Me') + var tree = context.SemanticModel.SyntaxTree; + var targetToken = await tree.GetTouchingTokenAsync(context.Position, context.CancellationToken).ConfigureAwait(false); + if (IsInstanceContext(tree, targetToken, context.SemanticModel, context.CancellationToken)) + { + var enclosingSymbol = context.SemanticModel.GetEnclosingSymbol(targetToken.SpanStart, context.CancellationToken); + while (enclosingSymbol is IMethodSymbol { MethodKind: MethodKind.LocalFunction or MethodKind.AnonymousFunction } method) + { + // It is allowed to reference the instance (`this`) within a local function or anonymous function, + // as long as the containing method allows it + enclosingSymbol = enclosingSymbol.ContainingSymbol; + } + + if (enclosingSymbol is IMethodSymbol { ContainingType: { } containingType }) + { + CheckCandidate(containingType, ThisOrMeKeyword); + } + } + + if (bestSymbol is not null) + { + context.DefaultValue = bestSymbolName; + return; + } + + // Local functions + void CheckCandidate(ISymbol candidate, string? overridingName = null) + { + if (candidate.GetSymbolType() is not { } symbolType) + { + return; + } + + if (requireExactType && !SymbolEqualityComparer.Default.Equals(context.Parameter.Type, symbolType)) + { + return; + } + + var conversion = context.SemanticModel.Compilation.ClassifyCommonConversion(symbolType, context.Parameter.Type); + if (!conversion.IsImplicit) + { + return; + } + + if (bestSymbol is not null && !IsNewConversionSameOrBetter(conversion)) { - context.DefaultValue = context.Parameter.Name; - return Task.CompletedTask; + if (!IsNewConversionSameOrBetter(conversion)) + return; + + if (!IsNewNameSameOrBetter(candidate)) + return; } + + bestSymbol = candidate; + bestSymbolName = overridingName ?? bestSymbol.Name; + bestConversion = conversion; } - return Task.CompletedTask; + bool IsNewConversionSameOrBetter(CommonConversion conversion) + { + if (bestConversion.IsIdentity && !conversion.IsIdentity) + return false; + + if (bestConversion.IsImplicit && !conversion.IsImplicit) + return false; + + return true; + } + + bool IsNewNameSameOrBetter(ISymbol symbol) + { + if (string.Equals(bestSymbol.Name, context.Parameter.Name)) + return string.Equals(symbol.Name, context.Parameter.Name); + + if (string.Equals(bestSymbol.Name, context.Parameter.Name, StringComparison.OrdinalIgnoreCase)) + return string.Equals(symbol.Name, context.Parameter.Name, StringComparison.OrdinalIgnoreCase); + + return true; + } } } } diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs index cc3fbda24b4a5..37fd238b56cce 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs @@ -125,9 +125,8 @@ private async Task DetermineNewDocumentAsync(Document document, Comple } // CodeGenerationOptions containing before and after - var options = new CodeGenerationOptions( - contextLocation: semanticModel.SyntaxTree.GetLocation(TextSpan.FromBounds(line.Start, line.Start)), - options: await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false)); + var context = new CodeGenerationContext( + contextLocation: semanticModel.SyntaxTree.GetLocation(TextSpan.FromBounds(line.Start, line.Start))); var generatedMember = await GenerateMemberAsync(overriddenMember, containingType, document, completionItem, cancellationToken).ConfigureAwait(false); generatedMember = _annotation.AddAnnotationToSymbol(generatedMember); @@ -135,15 +134,15 @@ private async Task DetermineNewDocumentAsync(Document document, Comple Document? memberContainingDocument = null; if (generatedMember.Kind == SymbolKind.Method) { - memberContainingDocument = await codeGenService.AddMethodAsync(document.Project.Solution, containingType, (IMethodSymbol)generatedMember, options, cancellationToken).ConfigureAwait(false); + memberContainingDocument = await codeGenService.AddMethodAsync(document.Project.Solution, containingType, (IMethodSymbol)generatedMember, context, cancellationToken).ConfigureAwait(false); } else if (generatedMember.Kind == SymbolKind.Property) { - memberContainingDocument = await codeGenService.AddPropertyAsync(document.Project.Solution, containingType, (IPropertySymbol)generatedMember, options, cancellationToken).ConfigureAwait(false); + memberContainingDocument = await codeGenService.AddPropertyAsync(document.Project.Solution, containingType, (IPropertySymbol)generatedMember, context, cancellationToken).ConfigureAwait(false); } else if (generatedMember.Kind == SymbolKind.Event) { - memberContainingDocument = await codeGenService.AddEventAsync(document.Project.Solution, containingType, (IEventSymbol)generatedMember, options, cancellationToken).ConfigureAwait(false); + memberContainingDocument = await codeGenService.AddEventAsync(document.Project.Solution, containingType, (IEventSymbol)generatedMember, context, cancellationToken).ConfigureAwait(false); } return memberContainingDocument; diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractExtensionMethodImportCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractExtensionMethodImportCompletionProvider.cs index 850ee376694c0..cf076d9636796 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractExtensionMethodImportCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractExtensionMethodImportCompletionProvider.cs @@ -31,7 +31,6 @@ protected override async Task AddCompletionItemsAsync( CompletionContext completionContext, SyntaxContext syntaxContext, HashSet namespaceInScope, - bool isExpandedCompletion, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Completion_ExtensionMethodImportCompletionProvider_GetCompletionItemsAsync, cancellationToken)) @@ -40,39 +39,20 @@ protected override async Task AddCompletionItemsAsync( if (TryGetReceiverTypeSymbol(syntaxContext, syntaxFacts, cancellationToken, out var receiverTypeSymbol)) { var ticks = Environment.TickCount; - using var nestedTokenSource = new CancellationTokenSource(); - using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(nestedTokenSource.Token, cancellationToken); var inferredTypes = completionContext.CompletionOptions.TargetTypedCompletionFilter ? syntaxContext.InferredTypes : ImmutableArray.Empty; - var getItemsTask = Task.Run(() => ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsAsync( + var result = await ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsAsync( completionContext.Document, completionContext.Position, receiverTypeSymbol, namespaceInScope, inferredTypes, - forceIndexCreation: isExpandedCompletion, + forceIndexCreation: completionContext.CompletionOptions.ForceExpandedCompletionIndexCreation, hideAdvancedMembers: completionContext.CompletionOptions.HideAdvancedMembers, - linkedTokenSource.Token), linkedTokenSource.Token); + cancellationToken).ConfigureAwait(false); - var timeoutInMilliseconds = completionContext.CompletionOptions.TimeoutInMillisecondsForExtensionMethodImportCompletion; - - // Timebox is enabled if timeout value is >= 0 and we are not triggered via expander - if (timeoutInMilliseconds >= 0 && !isExpandedCompletion) - { - // timeout == 0 means immediate timeout (for testing purpose) - if (timeoutInMilliseconds == 0 || await Task.WhenAny(getItemsTask, Task.Delay(timeoutInMilliseconds, linkedTokenSource.Token)).ConfigureAwait(false) != getItemsTask) - { - nestedTokenSource.Cancel(); - CompletionProvidersLogger.LogExtensionMethodCompletionTimeoutCount(); - return; - } - } - - // Either the timebox is not enabled, so we need to wait until the operation for complete, - // or there's no timeout, and we now have all completion items ready. - var result = await getItemsTask.ConfigureAwait(false); if (result is null) return; @@ -82,18 +62,11 @@ protected override async Task AddCompletionItemsAsync( // report telemetry: var totalTicks = Environment.TickCount - ticks; CompletionProvidersLogger.LogExtensionMethodCompletionTicksDataPoint( - totalTicks, result.GetSymbolsTicks, result.CreateItemsTicks, isExpandedCompletion, result.IsRemote); + totalTicks, result.GetSymbolsTicks, result.CreateItemsTicks, result.IsRemote); if (result.IsPartialResult) CompletionProvidersLogger.LogExtensionMethodCompletionPartialResultCount(); } - else - { - // If we can't get a valid receiver type, then we don't show expander as available. - // We need to set this explicitly here because we didn't do the (more expensive) symbol check inside - // `ShouldProvideCompletion` method above, which is intended for quick syntax based check. - completionContext.ExpandItemsAvailable = false; - } } } diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionProvider.cs index a7297f2185005..049b9115032ca 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionProvider.cs @@ -6,7 +6,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Completion.Log; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; @@ -21,10 +21,9 @@ namespace Microsoft.CodeAnalysis.Completion.Providers { internal abstract class AbstractImportCompletionProvider : LSPCompletionProvider, INotifyCommittingItemCompletionProvider { - protected abstract Task CreateContextAsync(Document document, int position, CancellationToken cancellationToken); - protected abstract ImmutableArray GetImportedNamespaces(SyntaxNode location, SemanticModel semanticModel, CancellationToken cancellationToken); + protected abstract Task> GetImportedNamespacesAsync(SyntaxContext syntaxContext, CancellationToken cancellationToken); protected abstract bool ShouldProvideCompletion(CompletionContext completionContext, SyntaxContext syntaxContext); - protected abstract Task AddCompletionItemsAsync(CompletionContext completionContext, SyntaxContext syntaxContext, HashSet namespacesInScope, bool isExpandedCompletion, CancellationToken cancellationToken); + protected abstract Task AddCompletionItemsAsync(CompletionContext completionContext, SyntaxContext syntaxContext, HashSet namespacesInScope, CancellationToken cancellationToken); protected abstract bool IsFinalSemicolonOfUsingOrExtern(SyntaxNode directive, SyntaxToken token); protected abstract Task ShouldProvideParenthesisCompletionAsync(Document document, CompletionItem item, char? commitKey, CancellationToken cancellationToken); protected abstract void LogCommit(); @@ -39,47 +38,38 @@ public Task NotifyCommittingItemAsync(Document document, CompletionItem item, ch public override async Task ProvideCompletionsAsync(CompletionContext completionContext) { + if (!completionContext.CompletionOptions.ShouldShowItemsFromUnimportNamspaces()) + return; + var cancellationToken = completionContext.CancellationToken; var document = completionContext.Document; - // We need to check for context before option values, so we can tell completion service that we are in a context to provide expanded items - // even though import completion might be disabled. This would show the expander in completion list which user can then use to explicitly ask for unimported items. var syntaxContext = await CreateContextAsync(document, completionContext.Position, cancellationToken).ConfigureAwait(false); if (!ShouldProvideCompletion(completionContext, syntaxContext)) { return; } - completionContext.ExpandItemsAvailable = true; - - // We will trigger import completion regardless of the option/experiment if extended items is being requested explicitly (via expander in completion list) - var isExpandedCompletion = completionContext.CompletionOptions.IsExpandedCompletion; - if (!isExpandedCompletion) - { - var importCompletionOptionValue = completionContext.CompletionOptions.ShowItemsFromUnimportedNamespaces; - - // Don't trigger import completion if the option value is "default" and the experiment is disabled for the user. - if (importCompletionOptionValue == false || - (importCompletionOptionValue == null && !completionContext.CompletionOptions.TypeImportCompletion)) - { - return; - } - } - // Find all namespaces in scope at current cursor location, // which will be used to filter so the provider only returns out-of-scope types. - var namespacesInScope = GetNamespacesInScope(document, syntaxContext, cancellationToken); - await AddCompletionItemsAsync(completionContext, syntaxContext, namespacesInScope, isExpandedCompletion, cancellationToken).ConfigureAwait(false); + var namespacesInScope = await GetNamespacesInScopeAsync(syntaxContext, cancellationToken).ConfigureAwait(false); + await AddCompletionItemsAsync(completionContext, syntaxContext, namespacesInScope, cancellationToken).ConfigureAwait(false); + } + + private static async Task CreateContextAsync(Document document, int position, CancellationToken cancellationToken) + { + // Need regular semantic model because we will use it to get imported namespace symbols. Otherwise we will try to + // reach outside of the span and ended up with "node not within syntax tree" error from the speculative model. + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + return document.GetRequiredLanguageService().CreateContext(document, semanticModel, position, cancellationToken); } - private HashSet GetNamespacesInScope(Document document, SyntaxContext syntaxContext, CancellationToken cancellationToken) + private async Task> GetNamespacesInScopeAsync(SyntaxContext syntaxContext, CancellationToken cancellationToken) { var semanticModel = syntaxContext.SemanticModel; + var document = syntaxContext.Document; - // The location is the containing node of the LeftToken, or the compilation unit itsef if LeftToken - // indicates the beginning of the document (i.e. no parent). - var location = syntaxContext.LeftToken.Parent ?? syntaxContext.SyntaxTree.GetRoot(cancellationToken); - var importedNamespaces = GetImportedNamespaces(location, semanticModel, cancellationToken); + var importedNamespaces = await GetImportedNamespacesAsync(syntaxContext, cancellationToken).ConfigureAwait(false); // This hashset will be used to match namespace names, so it must have the same case-sensitivity as the source language. var syntaxFacts = document.GetRequiredLanguageService(); @@ -127,12 +117,11 @@ public override async Task GetChangeAsync( // Add required using/imports directive. var addImportService = document.GetRequiredLanguageService(); var generator = document.GetRequiredLanguageService(); - var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var allowInHiddenRegions = document.CanAddImportsInHiddenRegions(); + var importsPlacement = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); var importNode = CreateImport(document, containingNamespace); var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - var rootWithImport = addImportService.AddImport(compilation, root, addImportContextNode!, importNode, generator, optionSet, allowInHiddenRegions, cancellationToken); + var rootWithImport = addImportService.AddImport(compilation, root, addImportContextNode!, importNode, generator, importsPlacement, cancellationToken); var documentWithImport = document.WithSyntaxRoot(rootWithImport); // This only formats the annotated import we just added, not the entire document. var formattedDocumentWithImport = await Formatter.FormatAsync(documentWithImport, Formatter.Annotation, cancellationToken: cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs index 9580a5f5b0f48..1f0dd229f4007 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs @@ -28,32 +28,26 @@ protected override void LogCommit() protected abstract ImmutableArray GetAliasDeclarationNodes(SyntaxNode node); - protected override async Task AddCompletionItemsAsync(CompletionContext completionContext, SyntaxContext syntaxContext, HashSet namespacesInScope, bool isExpandedCompletion, CancellationToken cancellationToken) + protected override async Task AddCompletionItemsAsync(CompletionContext completionContext, SyntaxContext syntaxContext, HashSet namespacesInScope, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Completion_TypeImportCompletionProvider_GetCompletionItemsAsync, cancellationToken)) { - var telemetryCounter = new TelemetryCounter(isExpandedCompletion); + var telemetryCounter = new TelemetryCounter(); var typeImportCompletionService = completionContext.Document.GetRequiredLanguageService(); - var itemsFromAllAssemblies = await typeImportCompletionService.GetAllTopLevelTypesAsync( + var (itemsFromAllAssemblies, isPartialResult) = await typeImportCompletionService.GetAllTopLevelTypesAsync( completionContext.Document.Project, syntaxContext, - forceCacheCreation: isExpandedCompletion, + forceCacheCreation: completionContext.CompletionOptions.ForceExpandedCompletionIndexCreation, completionContext.CompletionOptions, cancellationToken).ConfigureAwait(false); - if (itemsFromAllAssemblies == null) - { + var aliasTargetNamespaceToTypeNameMap = GetAliasTypeDictionary(completionContext.Document, syntaxContext, cancellationToken); + foreach (var items in itemsFromAllAssemblies) + AddItems(items, completionContext, namespacesInScope, aliasTargetNamespaceToTypeNameMap, telemetryCounter); + + if (isPartialResult) telemetryCounter.CacheMiss = true; - } - else - { - var aliasTargetNamespaceToTypeNameMap = GetAliasTypeDictionary(completionContext.Document, syntaxContext, cancellationToken); - foreach (var items in itemsFromAllAssemblies) - { - AddItems(items, completionContext, namespacesInScope, aliasTargetNamespaceToTypeNameMap, telemetryCounter); - } - } telemetryCounter.Report(); } @@ -165,16 +159,14 @@ static bool ShouldAddItem( private class TelemetryCounter { private readonly int _tick; - private readonly bool _isExpandedCompletion; public int ItemsCount { get; set; } public int ReferenceCount { get; set; } public bool CacheMiss { get; set; } - public TelemetryCounter(bool isExpandedCompletion) + public TelemetryCounter() { _tick = Environment.TickCount; - _isExpandedCompletion = isExpandedCompletion; } public void Report() @@ -186,7 +178,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, _isExpandedCompletion); + CompletionProvidersLogger.LogTypeImportCompletionTicksDataPoint(delta); 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 4cf59cf11053c..80e91930f5436 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionService.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionService.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -43,16 +42,16 @@ public Task WarmUpCacheAsync(Project? project, CancellationToken cancellationTok : GetCacheEntriesAsync(project, forceCacheCreation: true, cancellationToken); } - public async Task>?> GetAllTopLevelTypesAsync( + public async Task<(ImmutableArray>, bool)> GetAllTopLevelTypesAsync( Project currentProject, SyntaxContext syntaxContext, bool forceCacheCreation, CompletionOptions options, CancellationToken cancellationToken) { - var getCacheResults = await GetCacheEntriesAsync(currentProject, forceCacheCreation, cancellationToken).ConfigureAwait(false); + var (getCacheResults, isPartialResult) = await GetCacheEntriesAsync(currentProject, forceCacheCreation, cancellationToken).ConfigureAwait(false); - if (getCacheResults == null) + if (isPartialResult) { // We use a very simple approach to build the cache in the background: // queue a new task only if the previous task is completed, regardless of what @@ -67,12 +66,10 @@ public Task WarmUpCacheAsync(Project? project, CancellationToken cancellationTok s_cachingTask = Task.Run(() => WarmUpCacheAsync(workspace.CurrentSolution.GetProject(projectId), CancellationToken.None), CancellationToken.None); } } - - return null; } var currentCompilation = await currentProject.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - return getCacheResults.Value.SelectAsArray(GetItemsFromCacheResult); + return (getCacheResults.SelectAsArray(GetItemsFromCacheResult), isPartialResult); ImmutableArray GetItemsFromCacheResult(GetCacheResult cacheResult) { @@ -86,8 +83,9 @@ ImmutableArray GetItemsFromCacheResult(GetCacheResult cacheResul } } - private async Task?> GetCacheEntriesAsync(Project currentProject, bool forceCacheCreation, CancellationToken cancellationToken) + private async Task<(ImmutableArray results, bool isPartial)> GetCacheEntriesAsync(Project currentProject, bool forceCacheCreation, CancellationToken cancellationToken) { + var isPartialResult = false; var _ = ArrayBuilder.GetInstance(out var builder); var currentCompilation = await currentProject.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); @@ -96,8 +94,8 @@ ImmutableArray GetItemsFromCacheResult(GetCacheResult cacheResul var cacheResult = await GetCacheForProjectAsync(currentProject, forceCacheCreation: true, editorBrowsableInfo, cancellationToken).ConfigureAwait(false); // We always force create a cache for current project. - Debug.Assert(cacheResult.HasValue); - builder.Add(cacheResult!.Value); + Contract.ThrowIfFalse(cacheResult.HasValue); + builder.Add(cacheResult.Value); var solution = currentProject.Solution; var graph = solution.GetProjectDependencyGraph(); @@ -123,9 +121,7 @@ ImmutableArray GetItemsFromCacheResult(GetCacheResult cacheResul } else { - // If there's cache miss, we just don't return any item. - // This way, we will not block completion building our cache. - return null; + isPartialResult = true; } } } @@ -142,14 +138,12 @@ ImmutableArray GetItemsFromCacheResult(GetCacheResult cacheResul } else { - // If there's cache miss, we just don't return any item. - // This way, we will not block completion building our cache. - return null; + isPartialResult = true; } } } - return builder.ToImmutable(); + return (builder.ToImmutable(), isPartialResult); static bool HasGlobalAlias(MetadataReference? metadataReference) => metadataReference != null && (metadataReference.Properties.Aliases.IsEmpty || metadataReference.Properties.Aliases.Any(alias => alias == MetadataReferenceProperties.GlobalAlias)); diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.CacheEntry.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.CacheEntry.cs index bf949951b841e..adebb6e32dbde 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.CacheEntry.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.CacheEntry.cs @@ -63,7 +63,7 @@ public CacheEntry ToCacheEntry() _mapBuilder); } - public void AddItem(SyntaxTreeIndex syntaxIndex) + public void AddItem(TopLevelSyntaxTreeIndex syntaxIndex) { foreach (var (receiverType, symbolInfoIndices) in syntaxIndex.ReceiverTypeNameToExtensionMethodMap) { @@ -118,7 +118,7 @@ private static IImportCompletionCacheService GetCacheService continue; } - var info = await document.GetSyntaxTreeIndexAsync(loadOnly, cancellationToken).ConfigureAwait(false); + var info = await TopLevelSyntaxTreeIndex.GetIndexAsync(document, loadOnly, cancellationToken).ConfigureAwait(false); if (info == null) { return null; diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs index 2178bc9d9a4e8..d5328f6c85aa8 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs @@ -115,8 +115,8 @@ public static async Task GetUnimportedEx { // We use a very simple approach to build the cache in the background: // queue a new task only if the previous task is completed. This is to avoid - // queueing calculation for the same set of references repeatedly while - // index is being constrcuted, which might take some time. + // queuing calculation for the same set of references repeatedly while + // index is being constructed, which might take some time. if (s_indexingTask.IsCompleted) { // When building cache in the background, make sure we always use latest snapshot with full semantic @@ -152,7 +152,7 @@ private static ImmutableArray ConvertSymbolsTo var containingNamespacename = GetFullyQualifiedNamespaceName(symbol.ContainingNamespace, namespaceNameCache); var overloadKey = (containingNamespacename, symbol.Name, isGeneric: symbol.Arity > 0); - // Select the overload convertable to any targeted type (if any) and with minimum number of parameters to display + // Select the overload convertible to any targeted type (if any) and with minimum number of parameters to display if (overloadMap.TryGetValue(overloadKey, out var currentValue)) { if (currentValue.includeInTargetTypedCompletion == includeInTargetTypedCompletion) @@ -185,7 +185,7 @@ private static ImmutableArray ConvertSymbolsTo foreach (var ((containingNamespace, _, _), (bestSymbol, overloadCount, includeInTargetTypedCompletion)) in overloadMap) { - // To display the count of of additional overloads, we need to substract total by 1. + // To display the count of additional overloads, we need to subtract total by 1. var item = new SerializableImportCompletionItem( SymbolKey.CreateString(bestSymbol, cancellationToken), bestSymbol.Name, diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ITypeImportCompletionService.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ITypeImportCompletionService.cs index 9fa93de7c814c..0d52e7f9add59 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ITypeImportCompletionService.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ITypeImportCompletionService.cs @@ -21,7 +21,7 @@ internal interface ITypeImportCompletionService : ILanguageService /// Because items from each entity are cached as a separate array, we simply return them as is instead of an /// aggregated array to avoid unnecessary allocations. /// - Task>?> GetAllTopLevelTypesAsync( + Task<(ImmutableArray>, bool)> GetAllTopLevelTypesAsync( Project project, SyntaxContext syntaxContext, bool forceCacheCreation, diff --git a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs index 1ed01b322bd86..1720eb5ac567f 100644 --- a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs @@ -81,7 +81,6 @@ private async Task ConvertAsync(Document document, TextSpan span, bool Debug.Assert(anonymousType != null); var position = span.Start; - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -122,21 +121,18 @@ await ReplaceMatchingAnonymousTypesAsync( containingMember, anonymousObject, anonymousType, cancellationToken).ConfigureAwait(false); + var context = new CodeGenerationContext( + generateMembers: true, + sortMembers: false, + autoInsertionLocation: false); + + var codeGenOptions = await CodeGenerationOptions.FromDocumentAsync(context, document, cancellationToken).ConfigureAwait(false); + var codeGenService = document.GetRequiredLanguageService(); + // Then, actually insert the new class in the appropriate container. var container = anonymousObject.GetAncestor() ?? root; editor.ReplaceNode(container, (currentContainer, _) => - { - var codeGenService = document.GetRequiredLanguageService(); - var codeGenOptions = new CodeGenerationOptions( - generateMembers: true, - sortMembers: false, - autoInsertionLocation: false, - options: options, - parseOptions: root.SyntaxTree.Options); - - return codeGenService.AddNamedType( - currentContainer, namedTypeSymbol, codeGenOptions, cancellationToken); - }); + codeGenService.AddNamedType(currentContainer, namedTypeSymbol, codeGenOptions, cancellationToken)); var updatedDocument = document.WithSyntaxRoot(editor.GetChangedRoot()); diff --git a/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs index d5cc1f5d54cf0..8e626eb88a81d 100644 --- a/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs @@ -11,23 +11,22 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ConvertAutoPropertyToFullProperty { - internal abstract class AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider - : CodeRefactoringProvider + internal abstract class AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider : CodeRefactoringProvider where TPropertyDeclarationNode : SyntaxNode where TTypeDeclarationNode : SyntaxNode + where TCodeGenerationPreferences : CodeGenerationPreferences { internal abstract Task GetFieldNameAsync(Document document, IPropertySymbol propertySymbol, CancellationToken cancellationToken); internal abstract (SyntaxNode newGetAccessor, SyntaxNode newSetAccessor) GetNewAccessors( - DocumentOptionSet options, SyntaxNode property, string fieldName, SyntaxGenerator generator); + TCodeGenerationPreferences preferences, SyntaxNode property, string fieldName, SyntaxGenerator generator); internal abstract SyntaxNode GetPropertyWithoutInitializer(SyntaxNode property); internal abstract SyntaxNode GetInitializerValue(SyntaxNode property); - internal abstract SyntaxNode ConvertPropertyToExpressionBodyIfDesired(DocumentOptionSet options, SyntaxNode fullProperty); + internal abstract SyntaxNode ConvertPropertyToExpressionBodyIfDesired(TCodeGenerationPreferences preferences, SyntaxNode fullProperty); internal abstract SyntaxNode GetTypeBlock(SyntaxNode syntaxNode); public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) @@ -84,14 +83,18 @@ private async Task ExpandToFullPropertyAsync( SyntaxNode root, CancellationToken cancellationToken) { + Contract.ThrowIfNull(document.DocumentState.ParseOptions); + var generator = SyntaxGenerator.GetGenerator(document); - var workspace = document.Project.Solution.Workspace; - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var codeGenerator = document.GetRequiredLanguageService(); + var services = document.Project.Solution.Workspace.Services; + + var preferences = (TCodeGenerationPreferences)await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); // Create full property. If the auto property had an initial value // we need to remove it and later add it to the backing field var fieldName = await GetFieldNameAsync(document, propertySymbol, cancellationToken).ConfigureAwait(false); - var (newGetAccessor, newSetAccessor) = GetNewAccessors(options, property, fieldName, generator); + var (newGetAccessor, newSetAccessor) = GetNewAccessors(preferences, property, fieldName, generator); var fullProperty = generator .WithAccessorDeclarations( GetPropertyWithoutInitializer(property), @@ -99,8 +102,8 @@ private async Task ExpandToFullPropertyAsync( ? new SyntaxNode[] { newGetAccessor } : new SyntaxNode[] { newGetAccessor, newSetAccessor }) .WithLeadingTrivia(property.GetLeadingTrivia()); - fullProperty = ConvertPropertyToExpressionBodyIfDesired(options, fullProperty); - var editor = new SyntaxEditor(root, workspace); + fullProperty = ConvertPropertyToExpressionBodyIfDesired(preferences, fullProperty); + var editor = new SyntaxEditor(root, services); editor.ReplaceNode(property, fullProperty.WithAdditionalAnnotations(Formatter.Annotation)); // add backing field, plus initializer if it exists @@ -110,6 +113,7 @@ private async Task ExpandToFullPropertyAsync( propertySymbol.Type, fieldName, initializer: GetInitializerValue(property)); + var codeGenOptions = preferences.GetOptions(CodeGenerationContext.Default); var typeDeclaration = propertySymbol.ContainingType.DeclaringSyntaxReferences; foreach (var td in typeDeclaration) { @@ -117,7 +121,7 @@ private async Task ExpandToFullPropertyAsync( if (property.Ancestors().Contains(block)) { editor.ReplaceNode(block, (currentTypeDecl, _) - => CodeGenerator.AddFieldDeclaration(currentTypeDecl, newField, workspace) + => codeGenerator.AddField(currentTypeDecl, newField, codeGenOptions, cancellationToken) .WithAdditionalAnnotations(Formatter.Annotation)); } } diff --git a/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs index 1086407b4c04e..fc9cde67e6c2a 100644 --- a/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs @@ -120,8 +120,7 @@ protected static void IntroduceCollectionStatement( var collectionStatement = generator.LocalDeclarationStatement( type, collectionVariableToken, - foreachInfo.RequireExplicitCastInterface - ? generator.CastExpression(foreachInfo.ExplicitCastInterface, expression) : expression); + (foreachInfo.ExplicitCastInterface != null) ? generator.CastExpression(foreachInfo.ExplicitCastInterface, expression) : expression); // attach trivia to right place collectionStatement = collectionStatement.WithLeadingTrivia(foreachInfo.ForEachStatement.GetFirstToken().LeadingTrivia); @@ -422,8 +421,8 @@ private async Task ConvertForeachToForAsync( CancellationToken cancellationToken) { var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var workspace = document.Project.Solution.Workspace; - var editor = new SyntaxEditor(model.SyntaxTree.GetRoot(cancellationToken), workspace); + var services = document.Project.Solution.Workspace.Services; + var editor = new SyntaxEditor(model.SyntaxTree.GetRoot(cancellationToken), services); ConvertToForStatement(model, foreachInfo, editor, cancellationToken); @@ -431,7 +430,7 @@ private async Task ConvertForeachToForAsync( return document.WithSyntaxRoot(newRoot); } - protected class ForEachInfo + protected sealed class ForEachInfo { public ForEachInfo( ISemanticFactsService semanticFacts, string collectionNameSuggestion, string countName, @@ -440,8 +439,6 @@ public ForEachInfo( { SemanticFacts = semanticFacts; - RequireExplicitCastInterface = explicitCastInterface != null; - CollectionNameSuggestion = collectionNameSuggestion; CountName = countName; @@ -455,7 +452,6 @@ public ForEachInfo( public ISemanticFactsService SemanticFacts { get; } - public bool RequireExplicitCastInterface { get; } public string CollectionNameSuggestion { get; } public string CountName { get; } public ITypeSymbol? ExplicitCastInterface { get; } diff --git a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs index bd8c418eac6f0..a670cc0e6be90 100644 --- a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs +++ b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs @@ -148,7 +148,7 @@ private Task ApplyConversionAsync( bool convertToQuery, CancellationToken cancellationToken) { - var editor = new SyntaxEditor(converter.ForEachInfo.SemanticModel.SyntaxTree.GetRoot(cancellationToken), document.Project.Solution.Workspace); + var editor = new SyntaxEditor(converter.ForEachInfo.SemanticModel.SyntaxTree.GetRoot(cancellationToken), document.Project.Solution.Workspace.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/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs index 373fe90b1ecdf..14cb10e4ae3fe 100644 --- a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs @@ -267,7 +267,7 @@ private static ImmutableArray GetExpandedArguments( for (var i = 1; i < arguments.Count; i++) { var argumentExpression = syntaxFacts.GetExpressionOfArgument(GetArgument(arguments, i, syntaxFacts)); - var convertedType = argumentExpression == null ? null : semanticModel.GetTypeInfo(argumentExpression).ConvertedType; + var convertedType = semanticModel.GetTypeInfo(argumentExpression).ConvertedType; if (convertedType == null) { builder.Add((TExpressionSyntax)syntaxGenerator.AddParentheses(argumentExpression)); diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs index f07d17dd0827a..eb41179388067 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs @@ -554,19 +554,17 @@ private static async Task GenerateStructIntoContainingNamespaceAsync( var syntaxFacts = document.GetLanguageService(); var container = tupleExprOrTypeNode.GetAncestor() ?? root; + var codeGenService = document.GetRequiredLanguageService(); + var context = new CodeGenerationContext( + generateMembers: true, + sortMembers: false, + autoInsertionLocation: false); + + var options = await CodeGenerationOptions.FromDocumentAsync(context, document, cancellationToken).ConfigureAwait(false); + // Then, actually insert the new class in the appropriate container. editor.ReplaceNode(container, (currentContainer, _) => - { - var codeGenService = document.GetRequiredLanguageService(); - var options = new CodeGenerationOptions( - generateMembers: true, - sortMembers: false, - autoInsertionLocation: false, - parseOptions: root.SyntaxTree.Options); - - return codeGenService.AddNamedType( - currentContainer, namedTypeSymbol, options, cancellationToken); - }); + codeGenService.AddNamedType(currentContainer, namedTypeSymbol, options, cancellationToken)); } private static async Task ApplyChangesAsync( diff --git a/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs b/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs index 30632f9a3fef9..ec340ca746d19 100644 --- a/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs +++ b/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs @@ -47,11 +47,7 @@ public void ReportAnalyzerDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic dia return; } - var diagnosticData = (project != null) ? - DiagnosticData.Create(diagnostic, project) : - DiagnosticData.Create(diagnostic, Workspace.Options); - - ReportAnalyzerDiagnostic(analyzer, diagnosticData, project); + ReportAnalyzerDiagnostic(analyzer, DiagnosticData.Create(diagnostic, project), project); } public void ReportAnalyzerDiagnostic(DiagnosticAnalyzer analyzer, DiagnosticData diagnosticData, Project? project) diff --git a/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs b/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs index bd2bd92bb55c1..fb06d30cab4e1 100644 --- a/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs +++ b/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Diagnostics.Telemetry; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -21,7 +22,6 @@ namespace Microsoft.CodeAnalysis.Diagnostics { internal static partial class AnalyzerHelper { - // These are the error codes of the compiler warnings. // Keep the ids the same so that de-duplication against compiler errors // works in the error list (after a build). @@ -180,31 +180,27 @@ public static DiagnosticData CreateAnalyzerLoadFailureDiagnostic(AnalyzerLoadFai static string GetLanguageSpecificId(string? language, string noLanguageId, string csharpId, string vbId) => language == null ? noLanguageId : (language == LanguageNames.CSharp) ? csharpId : vbId; - string id, messageFormat, message; + string id, message; switch (e.ErrorCode) { case AnalyzerLoadFailureEventArgs.FailureErrorCode.UnableToLoadAnalyzer: id = GetLanguageSpecificId(language, WRN_UnableToLoadAnalyzerId, WRN_UnableToLoadAnalyzerIdCS, WRN_UnableToLoadAnalyzerIdVB); - messageFormat = FeaturesResources.Unable_to_load_Analyzer_assembly_0_colon_1; message = string.Format(FeaturesResources.Unable_to_load_Analyzer_assembly_0_colon_1, fullPath, e.Message); break; case AnalyzerLoadFailureEventArgs.FailureErrorCode.UnableToCreateAnalyzer: id = GetLanguageSpecificId(language, WRN_AnalyzerCannotBeCreatedId, WRN_AnalyzerCannotBeCreatedIdCS, WRN_AnalyzerCannotBeCreatedIdVB); - messageFormat = FeaturesResources.An_instance_of_analyzer_0_cannot_be_created_from_1_colon_2; message = string.Format(FeaturesResources.An_instance_of_analyzer_0_cannot_be_created_from_1_colon_2, e.TypeName, fullPath, e.Message); break; case AnalyzerLoadFailureEventArgs.FailureErrorCode.NoAnalyzers: id = GetLanguageSpecificId(language, WRN_NoAnalyzerInAssemblyId, WRN_NoAnalyzerInAssemblyIdCS, WRN_NoAnalyzerInAssemblyIdVB); - messageFormat = FeaturesResources.The_assembly_0_does_not_contain_any_analyzers; message = string.Format(FeaturesResources.The_assembly_0_does_not_contain_any_analyzers, fullPath); break; case AnalyzerLoadFailureEventArgs.FailureErrorCode.ReferencesFramework: id = GetLanguageSpecificId(language, WRN_AnalyzerReferencesNetFrameworkId, WRN_AnalyzerReferencesNetFrameworkIdCS, WRN_AnalyzerReferencesNetFrameworkIdVB); - messageFormat = FeaturesResources.The_assembly_0_containing_type_1_references_NET_Framework; message = string.Format(FeaturesResources.The_assembly_0_containing_type_1_references_NET_Framework, fullPath, e.TypeName); break; @@ -218,7 +214,6 @@ static string GetLanguageSpecificId(string? language, string noLanguageId, strin id, FeaturesResources.Roslyn_HostError, message, - messageFormat, severity: DiagnosticSeverity.Warning, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true, @@ -307,6 +302,32 @@ private static void AssertCompilation(Project project, Compilation compilation1) Contract.ThrowIfFalse(compilation1 == compilation2); } + /// + /// Return true if the given is not suppressed for the given project. + /// NOTE: This API is intended to be used only for performance optimization. + /// + public static bool IsAnalyzerEnabledForProject(DiagnosticAnalyzer analyzer, Project project) + { + var options = project.CompilationOptions; + if (options == null || analyzer == FileContentLoadAnalyzer.Instance || analyzer.IsCompilerAnalyzer()) + { + return true; + } + + // Check if user has disabled analyzer execution for this project or via options. + if (!project.State.RunAnalyzers || SolutionCrawlerOptions.GetBackgroundAnalysisScope(project) == BackgroundAnalysisScope.None) + { + return false; + } + + // NOTE: Previously we used to return "CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(options)" + // on this code path, which returns true if analyzer is suppressed through compilation options. + // However, this check is no longer correct as analyzers can be enabled/disabled for individual + // documents through .editorconfig files. So we pessimistically assume analyzer is not suppressed + // and let the core analyzer driver in the compiler layer handle skipping redundant analysis callbacks. + return true; + } + public static async Task> ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync( DocumentDiagnosticAnalyzer analyzer, Document document, diff --git a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs index 66714ac6169eb..106ace38abb01 100644 --- a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs @@ -231,6 +231,9 @@ public Task DocumentOpenAsync(Document document, CancellationToken cancellationT public Task NonSourceDocumentOpenAsync(TextDocument textDocument, CancellationToken cancellationToken) => Task.CompletedTask; + public Task ActiveDocumentSwitchedAsync(TextDocument document, CancellationToken cancellationToken) + => Task.CompletedTask; + public Task NewSolutionSnapshotAsync(Solution solution, CancellationToken cancellationToken) => Task.CompletedTask; diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticModeExtensions.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticModeExtensions.cs index c614d5dc13531..f6ca7e59ec83b 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticModeExtensions.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticModeExtensions.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics { internal static class DiagnosticModeExtensions { - private static DiagnosticMode GetDiagnosticMode(IGlobalOptionService globalOptions, Option2 option) + public static DiagnosticMode GetDiagnosticMode(this IGlobalOptionService globalOptions, Option2 option) { var diagnosticModeOption = globalOptions.GetOption(option); diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs index 32f80575a8386..be29c597d1f5e 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs @@ -217,12 +217,12 @@ private void OnCleared(object sender, EventArgs e) [Obsolete] ImmutableArray IDiagnosticService.GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics, CancellationToken cancellationToken) - => GetPushDiagnosticsAsync(workspace, projectId, documentId, id, includeSuppressedDiagnostics, InternalDiagnosticsOptions.NormalDiagnosticMode, cancellationToken).AsTask().WaitAndGetResult_CanCallOnBackground(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, Option2 diagnosticMode, CancellationToken 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); - public ValueTask> GetPushDiagnosticsAsync(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics, Option2 diagnosticMode, CancellationToken cancellationToken) + public ValueTask> GetPushDiagnosticsAsync(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) => GetDiagnosticsAsync(workspace, projectId, documentId, id, includeSuppressedDiagnostics, forPullDiagnostics: false, diagnosticMode, cancellationToken); private ValueTask> GetDiagnosticsAsync( @@ -232,13 +232,12 @@ private ValueTask> GetDiagnosticsAsync( object id, bool includeSuppressedDiagnostics, bool forPullDiagnostics, - Option2 diagnosticMode, + DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { // If this is a pull client, but pull diagnostics is not on, then they get nothing. Similarly, if this is a // push client and pull diagnostics are on, they get nothing. - var isPull = _globalOptions.IsPullDiagnostics(diagnosticMode); - if (forPullDiagnostics != isPull) + if (forPullDiagnostics != (diagnosticMode == DiagnosticMode.Pull)) return new ValueTask>(ImmutableArray.Empty); if (id != null) @@ -317,10 +316,10 @@ private async ValueTask> GetDiagnosticsAsync( return result.ToImmutable(); } - public ImmutableArray GetPullDiagnosticBuckets(Workspace workspace, ProjectId projectId, DocumentId documentId, Option2 diagnosticMode, CancellationToken cancellationToken) + public ImmutableArray GetPullDiagnosticBuckets(Workspace workspace, ProjectId projectId, DocumentId documentId, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) => GetDiagnosticBuckets(workspace, projectId, documentId, forPullDiagnostics: true, diagnosticMode, cancellationToken); - public ImmutableArray GetPushDiagnosticBuckets(Workspace workspace, ProjectId projectId, DocumentId documentId, Option2 diagnosticMode, CancellationToken cancellationToken) + public ImmutableArray GetPushDiagnosticBuckets(Workspace workspace, ProjectId projectId, DocumentId documentId, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) => GetDiagnosticBuckets(workspace, projectId, documentId, forPullDiagnostics: false, diagnosticMode, cancellationToken); private ImmutableArray GetDiagnosticBuckets( @@ -328,13 +327,12 @@ private ImmutableArray GetDiagnosticBuckets( ProjectId projectId, DocumentId documentId, bool forPullDiagnostics, - Option2 diagnosticMode, + DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { // If this is a pull client, but pull diagnostics is not on, then they get nothing. Similarly, if this is a // push client and pull diagnostics are on, they get nothing. - var isPull = _globalOptions.IsPullDiagnostics(diagnosticMode); - if (forPullDiagnostics != isPull) + if (forPullDiagnostics != (diagnosticMode == DiagnosticMode.Pull)) return ImmutableArray.Empty; using var _1 = ArrayBuilder.GetInstance(out var result); diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs index f12d8156595e4..e5637e7d681cb 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -25,12 +26,17 @@ internal partial class DiagnosticIncrementalAnalyzer /// Also returns empty diagnostics for suppressed analyzer. /// Returns null if the diagnostics need to be computed. /// - private async Task TryGetCachedDocumentAnalysisDataAsync( - TextDocument document, StateSet stateSet, AnalysisKind kind, CancellationToken cancellationToken) + private static DocumentAnalysisData? TryGetCachedDocumentAnalysisData( + TextDocument document, StateSet stateSet, + AnalysisKind kind, VersionStamp version, + BackgroundAnalysisScope analysisScope, bool isActiveDocument, + bool isOpenDocument, bool isGeneratedRazorDocument, + CancellationToken cancellationToken) { + Debug.Assert(isActiveDocument || isOpenDocument || isGeneratedRazorDocument); + try { - var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false); var state = stateSet.GetOrCreateActiveFileState(document.Id); var existingData = state.GetAnalysisData(kind); @@ -39,8 +45,9 @@ internal partial class DiagnosticIncrementalAnalyzer return existingData; } - // Perf optimization: Check whether analyzer is suppressed and avoid getting diagnostics if suppressed. - if (DiagnosticAnalyzerInfoCache.IsAnalyzerSuppressed(stateSet.Analyzer, document.Project)) + // Perf optimization: Check whether analyzer is suppressed for project or document and avoid getting diagnostics if suppressed. + if (!AnalyzerHelper.IsAnalyzerEnabledForProject(stateSet.Analyzer, document.Project) || + !IsAnalyzerEnabledForDocument(stateSet.Analyzer, analysisScope, isActiveDocument, isOpenDocument, isGeneratedRazorDocument)) { return new DocumentAnalysisData(version, existingData.Items, ImmutableArray.Empty); } @@ -51,6 +58,49 @@ internal partial class DiagnosticIncrementalAnalyzer { throw ExceptionUtilities.Unreachable; } + + static bool IsAnalyzerEnabledForDocument( + DiagnosticAnalyzer analyzer, + BackgroundAnalysisScope analysisScope, + bool isActiveDocument, + bool isOpenDocument, + bool isGeneratedRazorDocument) + { + Debug.Assert(!isActiveDocument || isOpenDocument || isGeneratedRazorDocument); + + if (isGeneratedRazorDocument) + { + // This is a generated Razor document, and they always want all analyzer diagnostics. + return true; + } + + if (analyzer.IsCompilerAnalyzer()) + { + // Compiler analyzer is treated specially. + // It is executed for all documents (open and closed) for 'BackgroundAnalysisScope.FullSolution' + // and executed for just open documents for other analysis scopes. + return analysisScope == BackgroundAnalysisScope.FullSolution || isOpenDocument; + } + else + { + return analysisScope switch + { + // Analyzers are disabled for all documents. + BackgroundAnalysisScope.None => false, + + // Analyzers are enabled for active document. + BackgroundAnalysisScope.ActiveFile => isActiveDocument, + + // Analyzers are enabled for all open documents. + BackgroundAnalysisScope.OpenFiles => isOpenDocument, + + // Analyzers are enabled for all documents. + BackgroundAnalysisScope.FullSolution => true, + + _ => throw ExceptionUtilities.UnexpectedValue(analysisScope) + }; + } + } } /// diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_BuildSynchronization.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_BuildSynchronization.cs index cba3f3d1b0bb4..2d389ca76d1b1 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_BuildSynchronization.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_BuildSynchronization.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -188,7 +189,6 @@ private static DiagnosticData CreateLiveDiagnostic(DiagnosticDescriptor descript descriptor.Id, descriptor.Category, diagnostic.Message, - descriptor.GetBingHelpMessage(), diagnostic.Severity, descriptor.DefaultSeverity, descriptor.IsEnabledByDefault, diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs index d73034d64dc17..9258b337a3e12 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs @@ -281,13 +281,12 @@ protected override async Task AppendDiagnosticsAsync(Project project, IEnumerabl private bool ShouldIncludeStateSet(Project project, StateSet stateSet) { - var infoCache = Owner.DiagnosticAnalyzerInfoCache; - if (infoCache.IsAnalyzerSuppressed(stateSet.Analyzer, project)) + if (!AnalyzerHelper.IsAnalyzerEnabledForProject(stateSet.Analyzer, project)) { return false; } - if (_diagnosticIds != null && infoCache.GetDiagnosticDescriptors(stateSet.Analyzer).All(d => !_diagnosticIds.Contains(d.Id))) + if (_diagnosticIds != null && Owner.DiagnosticAnalyzerInfoCache.GetDiagnosticDescriptors(stateSet.Analyzer).All(d => !_diagnosticIds.Contains(d.Id))) { return false; } diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 6bb483dfd0bd5..93530a95a6cea 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -86,7 +86,7 @@ public static async Task CreateAsync( CancellationToken cancellationToken) { var stateSets = owner._stateManager - .GetOrCreateStateSets(document.Project).Where(s => !owner.DiagnosticAnalyzerInfoCache.IsAnalyzerSuppressed(s.Analyzer, document.Project)); + .GetOrCreateStateSets(document.Project).Where(s => AnalyzerHelper.IsAnalyzerEnabledForProject(s.Analyzer, document.Project)); var compilationWithAnalyzers = await GetOrCreateCompilationWithAnalyzersAsync(document.Project, stateSets, includeSuppressedDiagnostics, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs index f775b51e9b8ea..ec3d5c385fea6 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs @@ -35,15 +35,25 @@ private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKi { try { - if (!AnalysisEnabled(document, _documentTrackingService)) + if (!document.SupportsDiagnostics()) + { + return; + } + + var isActiveDocument = _documentTrackingService.TryGetActiveDocument() == document.Id; + var isOpenDocument = document.IsOpen(); + var isGeneratedRazorDocument = document.Services.GetService()?.DiagnosticsLspClientName != null; + + // Only analyze open/active documents, unless it is a generated Razor document. + if (!isActiveDocument && !isOpenDocument && !isGeneratedRazorDocument) { - // to reduce allocations, here, we don't clear existing diagnostics since it is dealt by other entry point such as - // DocumentReset or DocumentClosed. return; } var stateSets = _stateManager.GetOrUpdateStateSets(document.Project); var compilationWithAnalyzers = await GetOrCreateCompilationWithAnalyzersAsync(document.Project, stateSets, cancellationToken).ConfigureAwait(false); + var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false); + var backgroundAnalysisScope = SolutionCrawlerOptions.GetBackgroundAnalysisScope(document.Project); // We split the diagnostic computation for document into following steps: // 1. Try to get cached diagnostics for each analyzer, while computing the set of analyzers that do not have cached diagnostics. @@ -56,7 +66,8 @@ private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKi using var _ = ArrayBuilder.GetInstance(out var nonCachedStateSets); foreach (var stateSet in stateSets) { - var data = await TryGetCachedDocumentAnalysisDataAsync(document, stateSet, kind, cancellationToken).ConfigureAwait(false); + var data = TryGetCachedDocumentAnalysisData(document, stateSet, kind, version, + backgroundAnalysisScope, isActiveDocument, isOpenDocument, isGeneratedRazorDocument, cancellationToken); if (data.HasValue) { // We need to persist and raise diagnostics for suppressed analyzer. @@ -132,7 +143,7 @@ private async Task AnalyzeProjectAsync(Project project, bool forceAnalyzerRun, C // this is perf optimization. we cache these result since we know the result. (no diagnostics) var activeAnalyzers = stateSets .Select(s => s.Analyzer) - .Where(a => !DiagnosticAnalyzerInfoCache.IsAnalyzerSuppressed(a, project) && !a.IsOpenFileOnly(options)); + .Where(a => AnalyzerHelper.IsAnalyzerEnabledForProject(a, project) && !a.IsOpenFileOnly(options)); // get driver only with active analyzers. var compilationWithAnalyzers = await AnalyzerHelper.CreateCompilationWithAnalyzersAsync(project, activeAnalyzers, includeSuppressedDiagnostics: true, cancellationToken).ConfigureAwait(false); @@ -256,6 +267,28 @@ private void RaiseDiagnosticsRemovedIfRequiredForClosedOrResetDocument(TextDocum RaiseDiagnosticsRemovedForDocument(document.Id, stateSets); } + public async Task ActiveDocumentSwitchedAsync(TextDocument document, CancellationToken cancellationToken) + { + // When the analysis scope is set to 'ActiveFile' and the active document is switched, + // we retrigger analysis of newly active document. + // For the remaining analysis scopes, we always analyze all the open files, so switching active + // documents between two open files doesn't require us to retrigger analysis of the newly active document. + if (SolutionCrawlerOptions.GetBackgroundAnalysisScope(document.Project) != BackgroundAnalysisScope.ActiveFile) + { + return; + } + + // First reset the document states. + await TextDocumentResetAsync(document, cancellationToken).ConfigureAwait(false); + + // Trigger syntax analysis. + await AnalyzeDocumentForKindAsync(document, AnalysisKind.Syntax, cancellationToken).ConfigureAwait(false); + + // Trigger semantic analysis for source documents. Non-source documents do not support semantic analysis. + if (document is Document) + await AnalyzeDocumentForKindAsync(document, AnalysisKind.Semantic, cancellationToken).ConfigureAwait(false); + } + public Task RemoveDocumentAsync(DocumentId documentId, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Diagnostics_RemoveDocument, GetRemoveLogMessage, documentId, CancellationToken.None)) @@ -330,31 +363,6 @@ public Task NewSolutionSnapshotAsync(Solution solution, CancellationToken cancel return Task.CompletedTask; } - private static bool AnalysisEnabled(TextDocument document, IDocumentTrackingService documentTrackingService) - { - if (document.Services.GetService()?.DiagnosticsLspClientName != null) - { - // This is a generated Razor document, and they want diagnostics, so let's report it - return true; - } - - if (!document.SupportsDiagnostics()) - { - return false; - } - - // change it to check active file (or visible files), not open files if active file tracking is enabled. - // otherwise, use open file. - if (SolutionCrawlerOptions.GetBackgroundAnalysisScope(document.Project) == BackgroundAnalysisScope.ActiveFile) - { - return documentTrackingService.TryGetActiveDocument() == document.Id; - } - else - { - return document.IsOpen(); - } - } - /// /// Return list of to be used for full solution analysis. /// diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticService.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticService.cs index d58da26d2f404..aeb2e2b27fbda 100644 --- a/src/Features/Core/Portable/Diagnostics/IDiagnosticService.cs +++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticService.cs @@ -6,7 +6,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Diagnostics { @@ -39,7 +38,7 @@ ImmutableArray GetDiagnostics( /// will return the requested diagnostics. ValueTask> GetPullDiagnosticsAsync( Workspace workspace, ProjectId? projectId, DocumentId? documentId, object? id, bool includeSuppressedDiagnostics, - Option2 diagnosticMode, CancellationToken cancellationToken); + DiagnosticMode diagnosticMode, CancellationToken cancellationToken); /// /// Get current diagnostics stored in IDiagnosticUpdateSource. @@ -50,7 +49,7 @@ ValueTask> GetPullDiagnosticsAsync( /// will return the requested diagnostics. ValueTask> GetPushDiagnosticsAsync( Workspace workspace, ProjectId? projectId, DocumentId? documentId, object? id, bool includeSuppressedDiagnostics, - Option2 diagnosticMode, CancellationToken cancellationToken); + DiagnosticMode diagnosticMode, CancellationToken cancellationToken); /// /// Get current buckets storing our grouped diagnostics. Specific buckets can be retrieved by calling > GetPushDiagnosticsAsync( /// will return the requested buckets. ImmutableArray GetPullDiagnosticBuckets( Workspace workspace, ProjectId? projectId, DocumentId? documentId, - Option2 diagnosticMode, CancellationToken cancellationToken); + DiagnosticMode diagnosticMode, CancellationToken cancellationToken); /// /// Get current buckets storing our grouped diagnostics. Specific buckets can be retrieved by calling GetPullDiagnosticBuckets( /// will return the requested buckets. ImmutableArray GetPushDiagnosticBuckets( Workspace workspace, ProjectId? projectId, DocumentId? documentId, - Option2 diagnosticMode, CancellationToken cancellationToken); + DiagnosticMode diagnosticMode, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticServiceExtensions.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticServiceExtensions.cs index 8dc9d85c619c1..4e0215808699e 100644 --- a/src/Features/Core/Portable/Diagnostics/IDiagnosticServiceExtensions.cs +++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticServiceExtensions.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -13,17 +12,17 @@ namespace Microsoft.CodeAnalysis.Diagnostics { internal static class IDiagnosticServiceExtensions { - public static ValueTask> GetPullDiagnosticsAsync(this IDiagnosticService service, DiagnosticBucket bucket, bool includeSuppressedDiagnostics, Option2 diagnosticMode, CancellationToken cancellationToken) + 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, Option2 diagnosticMode, CancellationToken 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, - Option2 diagnosticMode, + DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { return GetDiagnosticsAsync(service, document.Project.Solution.Workspace, document.Project, document, includeSuppressedDiagnostics, forPullDiagnostics: false, diagnosticMode, cancellationToken); @@ -33,7 +32,7 @@ public static ValueTask> GetPullDiagnosticsAsync( this IDiagnosticService service, Document document, bool includeSuppressedDiagnostics, - Option2 diagnosticMode, + DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { return GetDiagnosticsAsync(service, document.Project.Solution.Workspace, document.Project, document, includeSuppressedDiagnostics, forPullDiagnostics: true, diagnosticMode, cancellationToken); @@ -46,7 +45,7 @@ public static async ValueTask> GetDiagnosticsAsyn Document? document, bool includeSuppressedDiagnostics, bool forPullDiagnostics, - Option2 diagnosticMode, + DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { Contract.ThrowIfTrue(document != null && document.Project != project); diff --git a/src/Features/Core/Portable/Diagnostics/WorkspaceAnalyzerOptions.cs b/src/Features/Core/Portable/Diagnostics/WorkspaceAnalyzerOptions.cs index f9ae458634ce4..180f99a8a86d7 100644 --- a/src/Features/Core/Portable/Diagnostics/WorkspaceAnalyzerOptions.cs +++ b/src/Features/Core/Portable/Diagnostics/WorkspaceAnalyzerOptions.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -20,12 +21,27 @@ internal sealed class WorkspaceAnalyzerOptions : AnalyzerOptions { private readonly Solution _solution; + // IDE options for each encountered language + private ImmutableDictionary _ideOptionsCache; + public WorkspaceAnalyzerOptions(AnalyzerOptions options, Solution solution) : base(options.AdditionalFiles, options.AnalyzerConfigOptionsProvider) { _solution = solution; + _ideOptionsCache = ImmutableDictionary.Empty; } + public IdeAnalyzerOptions GetIdeOptions(string language) + => ImmutableInterlocked.GetOrAdd( + ref _ideOptionsCache, + language, + static (language, solution) => new IdeAnalyzerOptions( + FadeOutUnusedImports: solution.Options.GetOption(Fading.FadingOptions.Metadata.FadeOutUnusedImports, language), + FadeOutUnreachableCode: solution.Options.GetOption(Fading.FadingOptions.Metadata.FadeOutUnreachableCode, language), + ReportInvalidPlaceholdersInStringDotFormatCalls: solution.Options.GetOption(ValidateFormatString.ValidateFormatStringOption.ReportInvalidPlaceholdersInStringDotFormatCalls, language), + ReportInvalidRegexPatterns: solution.Options.GetOption(Features.EmbeddedLanguages.RegularExpressions.LanguageServices.RegularExpressionsOptions.ReportInvalidRegexPatterns, language)), + _solution); + public HostWorkspaceServices Services => _solution.Workspace.Services; [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/23582", OftenCompletesSynchronously = true)] @@ -60,9 +76,7 @@ public override bool Equals(object obj) } public override int GetHashCode() - { - return Hash.Combine(_solution.Workspace, - Hash.Combine(_solution.WorkspaceVersion, base.GetHashCode())); - } + => Hash.Combine(_solution.Workspace, + Hash.Combine(_solution.WorkspaceVersion, base.GetHashCode())); } } diff --git a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs index 783a329fc28ac..e1c0bf5be94fa 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs @@ -156,7 +156,7 @@ private static bool ShouldConsiderSymbol(ISymbol symbol) private async Task> FilterAndCreateSpansAsync( ImmutableArray references, Document startingDocument, IImmutableSet documentsToSearch, ISymbol symbol, - FindSymbols.FindReferencesSearchOptions options, CancellationToken cancellationToken) + FindReferencesSearchOptions options, CancellationToken cancellationToken) { var solution = startingDocument.Project.Solution; references = references.FilterToItemsToShow(options); diff --git a/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs index 13d2274a39045..1399c1eb60117 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs @@ -6,7 +6,7 @@ using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/Core/Portable/DocumentSpanExtensions.cs b/src/Features/Core/Portable/DocumentSpanExtensions.cs index 1088ab11c48a8..86e8a352321a1 100644 --- a/src/Features/Core/Portable/DocumentSpanExtensions.cs +++ b/src/Features/Core/Portable/DocumentSpanExtensions.cs @@ -14,14 +14,6 @@ namespace Microsoft.CodeAnalysis { internal static class DocumentSpanExtensions { - [Obsolete("Use CanNavigateToAsync instead", error: false)] - public static bool CanNavigateTo(this DocumentSpan documentSpan, CancellationToken cancellationToken) - { - var workspace = documentSpan.Document.Project.Solution.Workspace; - var service = workspace.Services.GetService(); - return service.CanNavigateToSpan(workspace, documentSpan.Document.Id, documentSpan.SourceSpan, cancellationToken); - } - public static Task CanNavigateToAsync(this DocumentSpan documentSpan, CancellationToken cancellationToken) { var workspace = documentSpan.Document.Project.Solution.Workspace; @@ -29,33 +21,17 @@ public static Task CanNavigateToAsync(this DocumentSpan documentSpan, Canc return service.CanNavigateToSpanAsync(workspace, documentSpan.Document.Id, documentSpan.SourceSpan, cancellationToken); } - private static (Workspace workspace, IDocumentNavigationService service, OptionSet options) GetNavigationParts( - DocumentSpan documentSpan, bool showInPreviewTab, bool activateTab) + private static (Workspace workspace, IDocumentNavigationService service) GetNavigationParts(DocumentSpan documentSpan) { var solution = documentSpan.Document.Project.Solution; var workspace = solution.Workspace; var service = workspace.Services.GetService(); - - var options = solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, showInPreviewTab); - options = options.WithChangedOption(NavigationOptions.ActivateTab, activateTab); - - return (workspace, service, options); - } - - [Obsolete("Use TryNavigateToAsync instead", error: false)] - public static bool TryNavigateTo(this DocumentSpan documentSpan, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) - { - var (workspace, service, options) = GetNavigationParts(documentSpan, showInPreviewTab, activateTab); - - // We're starting with one doc snapshot, but we're navigating to the current version of the doc. As such, - // the span we're trying to navigate to may no longer be there. Allow for that and don't crash in that case. - return service.TryNavigateToSpan( - workspace, documentSpan.Document.Id, documentSpan.SourceSpan, options, allowInvalidSpan: true, cancellationToken); + return (workspace, service); } - public static Task TryNavigateToAsync(this DocumentSpan documentSpan, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) + public static Task TryNavigateToAsync(this DocumentSpan documentSpan, NavigationOptions options, CancellationToken cancellationToken) { - var (workspace, service, options) = GetNavigationParts(documentSpan, showInPreviewTab, activateTab); + var (workspace, service) = GetNavigationParts(documentSpan); return service.TryNavigateToSpanAsync(workspace, documentSpan.Document.Id, documentSpan.SourceSpan, options, cancellationToken); } diff --git a/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentSnippetService.cs b/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentSnippetService.cs index 65d4fc8dd6a12..cca2980bbcff9 100644 --- a/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentSnippetService.cs +++ b/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentSnippetService.cs @@ -21,7 +21,6 @@ internal abstract class AbstractDocumentationCommentSnippetService GetDocumentationCommentStubLines(TMemberNode member); protected abstract SyntaxToken GetTokenToRight(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken); @@ -151,7 +150,7 @@ public bool IsValidTargetMember(SyntaxTree syntaxTree, SourceText text, int posi { var targetMember = documentationComment.ParentTrivia.Token.GetAncestor(); - if (targetMember == null || !IsMemberDeclaration(targetMember)) + if (targetMember == null || !SupportsDocumentationComments(targetMember)) { return null; } diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 1de120706d95d..ace0d22c36a0c 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -1191,11 +1191,22 @@ private void AnalyzeChangedMemberBody( // We expect OOM to be thrown during the analysis if the number of statements is too large. // In such case we report a rude edit for the document. If the host is actually running out of memory, // it might throw another OOM here or later on. - diagnostics.Add(new RudeEditDiagnostic( - (e is OutOfMemoryException) ? RudeEditKind.MemberBodyTooBig : RudeEditKind.MemberBodyInternalError, - GetBodyDiagnosticSpan(newBody, EditKind.Update), - newBody, - arguments: new[] { GetBodyDisplayName(newBody) })); + if (e is OutOfMemoryException) + { + diagnostics.Add(new RudeEditDiagnostic( + RudeEditKind.MemberBodyTooBig, + GetBodyDiagnosticSpan(newBody, EditKind.Update), + newBody, + arguments: new[] { GetBodyDisplayName(newBody) })); + } + else + { + diagnostics.Add(new RudeEditDiagnostic( + RudeEditKind.MemberBodyInternalError, + GetBodyDiagnosticSpan(newBody, EditKind.Update), + newBody, + arguments: new[] { GetBodyDisplayName(newBody), e.ToString() })); + } } } @@ -2266,7 +2277,7 @@ void AddCurrentSegment() if (documentLineEdits.Count > 0 && segment.oldStartLine > previousOldEndLine + 1) { Debug.Assert(previousOldEndLine >= 0); - documentLineEdits.Add(CreateZeroDeltaSourceLineUpdate(previousOldEndLine + 1)); + documentLineEdits.Add(new SourceLineUpdate(previousOldEndLine + 1, previousOldEndLine + 1)); previousLineDelta = 0; } @@ -2289,22 +2300,6 @@ void AddCurrentSegment() } } - // TODO: Currently the constructor SourceLineUpdate does not allow update with zero delta. - // Workaround until the debugger updates. - internal static SourceLineUpdate CreateZeroDeltaSourceLineUpdate(int line) - { - var result = new SourceLineUpdate(); - - // TODO: Currently the constructor SourceLineUpdate does not allow update with zero delta. - // Workaround until the debugger updates. - unsafe - { - Unsafe.Write(&result, ((long)line << 32) | (long)line); - } - - return result; - } - #endregion #region Semantic Analysis @@ -4800,7 +4795,7 @@ select clausesByQuery.First()) // Although local functions are non-virtual the Core CLR currently does not support adding any method to an interface. if (isInInterfaceDeclaration && IsLocalFunction(newLambda)) { - diagnostics.Add(new RudeEditDiagnostic(RudeEditKind.InsertLocalFunctionIntoInterfaceMethod, GetDiagnosticSpan(newLambda, EditKind.Insert), newLambda)); + diagnostics.Add(new RudeEditDiagnostic(RudeEditKind.InsertLocalFunctionIntoInterfaceMethod, GetDiagnosticSpan(newLambda, EditKind.Insert), newLambda, new string[] { GetDisplayName(newLambda, EditKind.Insert) })); } ReportMultiScopeCaptures(newLambdaBody1, newModel, newCaptures, newCaptures, newCapturesToClosureScopes, newCapturesIndex, reverseCapturesMap, diagnostics, isInsert: true, cancellationToken: cancellationToken); diff --git a/src/Features/Core/Portable/EditAndContinue/ActiveStatementsMap.cs b/src/Features/Core/Portable/EditAndContinue/ActiveStatementsMap.cs index 2297e638bcec4..81951a44c0655 100644 --- a/src/Features/Core/Portable/EditAndContinue/ActiveStatementsMap.cs +++ b/src/Features/Core/Portable/EditAndContinue/ActiveStatementsMap.cs @@ -141,9 +141,9 @@ private static bool TryGetUpToDateSpan(ManagedActiveStatementDebugInfo activeSta { foreach (var region in regionsInMethod) { - if (region.Span.Span.Contains(activeSpan) && activeStatementInfo.DocumentName == region.Span.Path) + if (region.OldSpan.Span.Contains(activeSpan) && activeStatementInfo.DocumentName == region.OldSpan.Path) { - newSpan = activeSpan.AddLineDelta(region.LineDelta); + newSpan = region.NewSpan.Span; return true; } } diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 65e45cd4e71d2..50303676177fb 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -659,7 +659,7 @@ public async ValueTask>> GetB var oldDocumentActiveStatements = await baseActiveStatements.GetOldActiveStatementsAsync(analyzer, oldDocument, cancellationToken).ConfigureAwait(false); var analysis = await analyzer.AnalyzeDocumentAsync( - LastCommittedSolution.GetRequiredProject(documentId.ProjectId), + oldProject, EditSession.BaseActiveStatements, newDocument, newActiveStatementSpans: ImmutableArray.Empty, diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index 93102bc0e7b10..b76bf921af927 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -153,8 +153,10 @@ internal EditSession( /// Errors to be reported when a project is updated but the corresponding module does not support EnC. /// /// if the module is not loaded. - public async Task?> GetModuleDiagnosticsAsync(Guid mvid, string projectDisplayName, CancellationToken cancellationToken) + public async Task?> GetModuleDiagnosticsAsync(Guid mvid, Project oldProject, Project newProject, ImmutableArray documentAnalyses, CancellationToken cancellationToken) { + Contract.ThrowIfTrue(documentAnalyses.IsEmpty); + var availability = await DebuggingSession.DebuggerService.GetAvailabilityAsync(mvid, cancellationToken).ConfigureAwait(false); if (availability.Status == ManagedHotReloadAvailabilityStatus.ModuleNotLoaded) { @@ -167,7 +169,69 @@ internal EditSession( } var descriptor = EditAndContinueDiagnosticDescriptors.GetModuleDiagnosticDescriptor(availability.Status); - return ImmutableArray.Create(Diagnostic.Create(descriptor, Location.None, new[] { projectDisplayName, availability.LocalizedMessage })); + var messageArgs = new[] { newProject.Name, availability.LocalizedMessage }; + + using var _ = ArrayBuilder.GetInstance(out var diagnostics); + + await foreach (var location in CreateChangedLocationsAsync(oldProject, newProject, documentAnalyses, cancellationToken).ConfigureAwait(false)) + { + diagnostics.Add(Diagnostic.Create(descriptor, location, messageArgs)); + } + + return diagnostics.ToImmutable(); + } + + private static async IAsyncEnumerable CreateChangedLocationsAsync(Project oldProject, Project newProject, ImmutableArray documentAnalyses, [EnumeratorCancellation] CancellationToken cancellationToken) + { + var hasRemovedOrAddedDocument = false; + foreach (var documentAnalysis in documentAnalyses) + { + if (!documentAnalysis.HasChanges) + { + continue; + } + + var oldDocument = await oldProject.GetDocumentAsync(documentAnalysis.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + var newDocument = await newProject.GetDocumentAsync(documentAnalysis.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + if (oldDocument == null || newDocument == null) + { + hasRemovedOrAddedDocument = true; + continue; + } + + var oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); + var newText = await newDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); + var newTree = await newDocument.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + + // document location: + yield return Location.Create(newTree, GetFirstLineDifferenceSpan(oldText, newText)); + } + + // project location: + if (hasRemovedOrAddedDocument) + { + yield return Location.None; + } + } + + private static TextSpan GetFirstLineDifferenceSpan(SourceText oldText, SourceText newText) + { + var oldLineCount = oldText.Lines.Count; + var newLineCount = newText.Lines.Count; + + for (var i = 0; i < Math.Min(oldLineCount, newLineCount); i++) + { + var oldLineSpan = oldText.Lines[i].Span; + var newLineSpan = newText.Lines[i].Span; + if (oldLineSpan != newLineSpan || !oldText.GetSubText(oldLineSpan).ContentEquals(newText.GetSubText(newLineSpan))) + { + return newText.Lines[i].Span; + } + } + + return (oldLineCount == newLineCount) ? default : + (newLineCount > oldLineCount) ? newText.Lines[oldLineCount].Span : + TextSpan.FromBounds(newText.Lines[newLineCount - 1].End, newText.Lines[newLineCount - 1].EndIncludingLineBreak); } private async Task GetCapabilitiesAsync(CancellationToken cancellationToken) @@ -780,10 +844,20 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution diagnostics.Add((newProject.Id, documentDiagnostics)); } + var projectSummary = GetProjectAnalysisSymmary(changedDocumentAnalyses); + if (projectSummary == ProjectAnalysisSummary.NoChanges) + { + continue; + } + + // PopulateChangedAndAddedDocumentsAsync returns no changes if base project does not exist + var oldProject = oldSolution.GetProject(newProject.Id); + Contract.ThrowIfNull(oldProject); + // 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. - var (moduleDiagnostics, isModuleLoaded) = await GetModuleDiagnosticsAsync(mvid, newProject.Name, cancellationToken).ConfigureAwait(false); + var (moduleDiagnostics, isModuleLoaded) = await GetModuleDiagnosticsAsync(mvid, oldProject, newProject, changedDocumentAnalyses, cancellationToken).ConfigureAwait(false); var isModuleEncBlocked = isModuleLoaded && !moduleDiagnostics.IsEmpty; if (isModuleEncBlocked) @@ -792,7 +866,6 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution isBlocked = true; } - var projectSummary = GetProjectAnalysisSymmary(changedDocumentAnalyses); if (projectSummary == ProjectAnalysisSummary.CompilationErrors) { // only remember the first syntax error we encounter: @@ -833,10 +906,6 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution EditAndContinueWorkspaceService.Log.Write("Emitting update of '{0}' [0x{1:X8}]", newProject.Id.DebugName, newProject.Id); - // PopulateChangedAndAddedDocumentsAsync returns no changes if base project does not exist - var oldProject = oldSolution.GetProject(newProject.Id); - Contract.ThrowIfNull(oldProject); - var oldCompilation = await oldProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var newCompilation = await newProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(oldCompilation); @@ -1011,8 +1080,7 @@ void AddNonRemappableRegion(SourceFileSpan oldSpan, SourceFileSpan newSpan, bool // when break state was entered and now being updated (regardless of whether the active span changed or not). if (isMethodUpdated) { - var lineDelta = oldSpan.Span.GetLineDelta(newSpan: newSpan.Span); - nonRemappableRegionsBuilder.Add((methodId, new NonRemappableRegion(oldSpan, lineDelta, isExceptionRegion))); + nonRemappableRegionsBuilder.Add((methodId, new NonRemappableRegion(oldSpan, newSpan, isExceptionRegion))); } else if (!isExceptionRegion) { @@ -1024,7 +1092,7 @@ void AddNonRemappableRegion(SourceFileSpan oldSpan, SourceFileSpan newSpan, bool // That said, we still add a non-remappable region for this active statement, so that we know in future sessions // that this active statement existed and its span has not changed. We don't report these regions to the debugger, // but we use them to map active statement spans to the baseline snapshots of following edit sessions. - nonRemappableRegionsBuilder.Add((methodId, new NonRemappableRegion(oldSpan, lineDelta: 0, isExceptionRegion: false))); + nonRemappableRegionsBuilder.Add((methodId, new NonRemappableRegion(oldSpan, oldSpan, isExceptionRegion: false))); } } else if (oldSpan.Span != newSpan.Span) @@ -1080,17 +1148,17 @@ void AddNonRemappableRegion(SourceFileSpan oldSpan, SourceFileSpan newSpan, bool foreach (var region in regionsInMethod) { // We have calculated changes against a base snapshot (last break state): - var baseSpan = region.Span.AddLineDelta(region.LineDelta); + var baseSpan = region.NewSpan; NonRemappableRegion newRegion; if (changedNonRemappableSpans.TryGetValue((methodInstance.Method, baseSpan), out var newSpan)) { // all spans must be of the same size: Debug.Assert(newSpan.Span.End.Line - newSpan.Span.Start.Line == baseSpan.Span.End.Line - baseSpan.Span.Start.Line); - Debug.Assert(region.Span.Span.End.Line - region.Span.Span.Start.Line == baseSpan.Span.End.Line - baseSpan.Span.Start.Line); - Debug.Assert(newSpan.Path == region.Span.Path); + Debug.Assert(region.OldSpan.Span.End.Line - region.OldSpan.Span.Start.Line == baseSpan.Span.End.Line - baseSpan.Span.Start.Line); + Debug.Assert(newSpan.Path == region.OldSpan.Path); - newRegion = region.WithLineDelta(region.Span.Span.GetLineDelta(newSpan: newSpan.Span)); + newRegion = region.WithNewSpan(newSpan); } else { @@ -1123,8 +1191,8 @@ void AddNonRemappableRegion(SourceFileSpan oldSpan, SourceFileSpan newSpan, bool r => r.Region.IsExceptionRegion, r => new ManagedExceptionRegionUpdate( r.Method, - -r.Region.LineDelta, - r.Region.Span.AddLineDelta(r.Region.LineDelta).Span.ToSourceSpan())); + -r.Region.OldSpan.Span.GetLineDelta(r.Region.NewSpan.Span), + r.Region.NewSpan.Span.ToSourceSpan())); } } } diff --git a/src/Features/Core/Portable/EditAndContinue/ManagedModuleUpdateStatusEx.cs b/src/Features/Core/Portable/EditAndContinue/ManagedModuleUpdateStatusEx.cs deleted file mode 100644 index f40323761a24d..0000000000000 --- a/src/Features/Core/Portable/EditAndContinue/ManagedModuleUpdateStatusEx.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.EditAndContinue.Contracts; - -namespace Microsoft.CodeAnalysis.EditAndContinue -{ - // Temporary values in main branch - we do not sistinguish between RudeEdit and Blocked. - // To be replaced with actual values from Debugger.Contracts in vs-deps branch. - internal static class ManagedModuleUpdateStatusEx - { - public const ManagedModuleUpdateStatus RestartRequired = ManagedModuleUpdateStatus.RestartRequired; - public const ManagedModuleUpdateStatus Blocked = ManagedModuleUpdateStatus.Blocked; - } -} diff --git a/src/Features/Core/Portable/EditAndContinue/NonRemappableRegion.cs b/src/Features/Core/Portable/EditAndContinue/NonRemappableRegion.cs index 446cfe5d6535f..6a55622dd8b73 100644 --- a/src/Features/Core/Portable/EditAndContinue/NonRemappableRegion.cs +++ b/src/Features/Core/Portable/EditAndContinue/NonRemappableRegion.cs @@ -14,22 +14,22 @@ namespace Microsoft.CodeAnalysis.EditAndContinue /// /// Pre-remap PDB span. /// - public readonly SourceFileSpan Span; + public readonly SourceFileSpan OldSpan; /// - /// Difference between new span and pre-remap span (new = old + delta). + /// New PDB span. /// - public readonly int LineDelta; + public readonly SourceFileSpan NewSpan; /// /// True if the region represents an exception region, false if it represents an active statement. /// public readonly bool IsExceptionRegion; - public NonRemappableRegion(SourceFileSpan span, int lineDelta, bool isExceptionRegion) + public NonRemappableRegion(SourceFileSpan oldSpan, SourceFileSpan newSpan, bool isExceptionRegion) { - Span = span; - LineDelta = lineDelta; + OldSpan = oldSpan; + NewSpan = newSpan; IsExceptionRegion = isExceptionRegion; } @@ -37,12 +37,12 @@ public override bool Equals(object? obj) => obj is NonRemappableRegion region && Equals(region); public bool Equals(NonRemappableRegion other) - => Span.Equals(other.Span) && - LineDelta == other.LineDelta && + => OldSpan.Equals(other.OldSpan) && + NewSpan.Equals(other.NewSpan) && IsExceptionRegion == other.IsExceptionRegion; public override int GetHashCode() - => Hash.Combine(Span.GetHashCode(), Hash.Combine(IsExceptionRegion, LineDelta)); + => Hash.Combine(OldSpan.GetHashCode(), Hash.Combine(IsExceptionRegion, NewSpan.GetHashCode())); public static bool operator ==(NonRemappableRegion left, NonRemappableRegion right) => left.Equals(right); @@ -50,10 +50,10 @@ public override int GetHashCode() public static bool operator !=(NonRemappableRegion left, NonRemappableRegion right) => !(left == right); - public NonRemappableRegion WithLineDelta(int value) - => new(Span, value, IsExceptionRegion); + public NonRemappableRegion WithNewSpan(SourceFileSpan newSpan) + => new(OldSpan, newSpan, IsExceptionRegion); internal string GetDebuggerDisplay() - => $"{(IsExceptionRegion ? "ER" : "AS")} {Span} δ={LineDelta}"; + => $"{(IsExceptionRegion ? "ER" : "AS")} {OldSpan} => {NewSpan.Span}"; } } diff --git a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs index 6832ab34f6774..37526e41b6a9b 100644 --- a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs +++ b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs @@ -4,19 +4,16 @@ using System; using System.Collections.Immutable; -using System.Composition; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.EditAndContinue.Contracts; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.EditAndContinue.Contracts; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue { @@ -41,7 +38,7 @@ public void Dispose() private IEditAndContinueWorkspaceService GetLocalService() => _workspace.Services.GetRequiredService(); - public async ValueTask BreakStateOrCapabilitiesChangedAsync(IDiagnosticAnalyzerService diagnosticService, bool? inBreakState, CancellationToken cancellationToken) + public async ValueTask BreakStateOrCapabilitiesChangedAsync(IDiagnosticAnalyzerService diagnosticService, EditAndContinueDiagnosticUpdateSource diagnosticUpdateSource, bool? inBreakState, CancellationToken cancellationToken) { ImmutableArray documentsToReanalyze; @@ -61,6 +58,9 @@ public async ValueTask BreakStateOrCapabilitiesChangedAsync(IDiagnosticAnalyzerS // clear all reported rude edits: diagnosticService.Reanalyze(_workspace, documentIds: documentsToReanalyze); + + // clear emit/apply diagnostics reported previously: + diagnosticUpdateSource.ClearDiagnostics(); } public async ValueTask EndDebuggingSessionAsync(Solution compileTimeSolution, EditAndContinueDiagnosticUpdateSource diagnosticUpdateSource, IDiagnosticAnalyzerService diagnosticService, CancellationToken cancellationToken) @@ -154,7 +154,7 @@ public async ValueTask HasChangesAsync(Solution solution, ActiveStatementS } else { - moduleUpdates = new ManagedModuleUpdates(ManagedModuleUpdateStatusEx.RestartRequired, ImmutableArray.Empty); + moduleUpdates = new ManagedModuleUpdates(ManagedModuleUpdateStatus.RestartRequired, ImmutableArray.Empty); diagnosticData = ImmutableArray.Empty; rudeEdits = ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)>.Empty; syntaxError = null; @@ -170,9 +170,9 @@ public async ValueTask HasChangesAsync(Solution solution, ActiveStatementS Location.None, string.Format(descriptor.MessageFormat.ToString(), "", e.Message)); - diagnosticData = ImmutableArray.Create(DiagnosticData.Create(diagnostic, solution.Options)); + diagnosticData = ImmutableArray.Create(DiagnosticData.Create(diagnostic, project: null)); rudeEdits = ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)>.Empty; - moduleUpdates = new ManagedModuleUpdates(ManagedModuleUpdateStatusEx.RestartRequired, ImmutableArray.Empty); + moduleUpdates = new ManagedModuleUpdates(ManagedModuleUpdateStatus.RestartRequired, ImmutableArray.Empty); syntaxError = null; } diff --git a/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs b/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs index ed05d4ae20545..5a84e54d33718 100644 --- a/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs +++ b/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs @@ -40,7 +40,7 @@ public static SolutionUpdate Blocked( Diagnostic? syntaxError, bool hasEmitErrors) => new( - new(syntaxError != null || hasEmitErrors ? ManagedModuleUpdateStatusEx.Blocked : ManagedModuleUpdateStatusEx.RestartRequired, ImmutableArray.Empty), + new(syntaxError != null || hasEmitErrors ? ManagedModuleUpdateStatus.Blocked : ManagedModuleUpdateStatus.RestartRequired, ImmutableArray.Empty), ImmutableArray<(Guid, ImmutableArray<(ManagedModuleMethodId, NonRemappableRegion)>)>.Empty, ImmutableArray<(ProjectId, EmitBaseline)>.Empty, diagnostics, diff --git a/src/Features/Core/Portable/EmbeddedLanguages/AbstractEmbeddedLanguagesFeaturesProvider.cs b/src/Features/Core/Portable/EmbeddedLanguages/AbstractEmbeddedLanguagesFeaturesProvider.cs index ce1bf35775ce2..523a61d9890e2 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/AbstractEmbeddedLanguagesFeaturesProvider.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/AbstractEmbeddedLanguagesFeaturesProvider.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime; -using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages { @@ -23,6 +22,7 @@ protected AbstractEmbeddedLanguageFeaturesProvider(EmbeddedLanguageInfo info) : Languages = ImmutableArray.Create( new DateAndTimeEmbeddedLanguageFeatures(info), new RegexEmbeddedLanguage(this, info), + new JsonEmbeddedLanguage(info), new FallbackEmbeddedLanguage(info)); } @@ -33,6 +33,6 @@ protected AbstractEmbeddedLanguageFeaturesProvider(EmbeddedLanguageInfo info) : /// /// The original string token that is being /// inserted into. - internal abstract string EscapeText(string text, SyntaxToken token); + public abstract string EscapeText(string text, SyntaxToken token); } } diff --git a/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs new file mode 100644 index 0000000000000..ca27223d98a35 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.cs @@ -0,0 +1,329 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; +using System.Threading; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages +{ + internal abstract class AbstractLanguageDetector + where TOptions : struct, Enum + where TTree : class + { + protected readonly EmbeddedLanguageInfo Info; + + private readonly string _stringSyntaxAttributeName; + private readonly LanguageCommentDetector _commentDetector; + + protected AbstractLanguageDetector( + string stringSyntaxAttributeName, + EmbeddedLanguageInfo info, + LanguageCommentDetector commentDetector) + { + _stringSyntaxAttributeName = stringSyntaxAttributeName; + Info = info; + _commentDetector = commentDetector; + } + + /// + /// Whether or not this is an argument to a well known api for this language (like Regex.Match or JToken.Parse). + /// We light up support if we detect these, even if these APIs don't have the StringSyntaxAttribute attribute on + /// them. That way users can get a decent experience even on downlevel frameworks. + /// + protected abstract bool IsArgumentToWellKnownAPI(SyntaxToken token, SyntaxNode argumentNode, SemanticModel semanticModel, CancellationToken cancellationToken, out TOptions options); + + /// + /// Tries to parse out an appropriate language tree given the characters in this string literal. + /// + protected abstract TTree? TryParse(VirtualCharSequence chars, TOptions options); + + /// + /// Giving a sibling argument expression to the string literal, attempts to determine if they correspond to + /// options for that language. For example with new Regex("[a-z]", RegexOptions.CaseInsensitive) the + /// second argument's expression defines options that control how the literal is parsed. + /// + protected abstract bool TryGetOptions(SemanticModel semanticModel, ITypeSymbol exprType, SyntaxNode expr, CancellationToken cancellationToken, out TOptions options); + + // Most embedded languages don't support being in an interpolated string text token. + protected virtual bool IsEmbeddedLanguageInterpolatedStringTextToken(SyntaxToken token, SemanticModel semanticModel, CancellationToken cancellationToken) + => false; + + /// + /// What options we should assume by default if we're matched up against a symbol that has a [StringSyntax] + /// attribute on it. + /// + protected virtual TOptions GetStringSyntaxDefaultOptions() + => default; + + private bool HasLanguageComment( + SyntaxToken token, ISyntaxFacts syntaxFacts, out TOptions options) + { + if (HasLanguageComment(token.GetPreviousToken().TrailingTrivia, syntaxFacts, out options)) + return true; + + for (var node = token.Parent; node != null; node = node.Parent) + { + if (HasLanguageComment(node.GetLeadingTrivia(), syntaxFacts, out options)) + return true; + + // Stop walking up once we hit a statement. We don't need/want statements higher up the parent chain to + // have any impact on this token. + if (syntaxFacts.IsStatement(node)) + break; + } + + options = default; + return false; + } + + private bool HasLanguageComment( + SyntaxTriviaList list, ISyntaxFacts syntaxFacts, out TOptions options) + { + foreach (var trivia in list) + { + if (HasLanguageComment(trivia, syntaxFacts, out options)) + return true; + } + + options = default; + return false; + } + + private bool HasLanguageComment( + SyntaxTrivia trivia, ISyntaxFacts syntaxFacts, out TOptions options) + { + if (syntaxFacts.IsRegularComment(trivia)) + { + // Note: ToString on SyntaxTrivia is non-allocating. It will just return the + // underlying text that the trivia is already pointing to. + var text = trivia.ToString(); + if (_commentDetector.TryMatch(text, out options)) + return true; + } + + options = default; + return false; + } + + public bool IsEmbeddedLanguageToken(SyntaxToken token, SemanticModel semanticModel, CancellationToken cancellationToken, out TOptions options) + { + options = default; + + if (Info.IsAnyStringLiteral(token.RawKind)) + return IsEmbeddedLanguageStringLiteralToken(token, semanticModel, cancellationToken, out options); + + if (token.RawKind == Info.SyntaxKinds.InterpolatedStringTextToken) + { + options = default; + return IsEmbeddedLanguageInterpolatedStringTextToken(token, semanticModel, cancellationToken); + } + + return false; + } + + private bool IsEmbeddedLanguageStringLiteralToken(SyntaxToken token, SemanticModel semanticModel, CancellationToken cancellationToken, out TOptions options) + { + options = default; + var syntaxFacts = Info.SyntaxFacts; + if (!syntaxFacts.IsLiteralExpression(token.Parent)) + return false; + + if (HasLanguageComment(token, syntaxFacts, out options)) + return true; + + var parent = syntaxFacts.WalkUpParentheses(token.Parent); + + if (syntaxFacts.IsArgument(parent.Parent)) + { + var argument = parent.Parent; + if (IsArgumentToWellKnownAPI(token, argument, semanticModel, cancellationToken, out options)) + return true; + + if (IsArgumentToParameterWithMatchingStringSyntaxAttribute(semanticModel, argument, cancellationToken, out options)) + return true; + } + else if (syntaxFacts.IsAttributeArgument(parent.Parent)) + { + var argument = parent.Parent; + if (IsArgumentToAttributeParameterWithMatchingStringSyntaxAttribute(semanticModel, argument, cancellationToken, out options)) + return true; + } + else + { + var statement = parent.FirstAncestorOrSelf(syntaxFacts.IsStatement); + if (syntaxFacts.IsSimpleAssignmentStatement(statement)) + { + syntaxFacts.GetPartsOfAssignmentStatement(statement, out var left, out var right); + if (parent == right && + IsFieldOrPropertyWithMatchingStringSyntaxAttribute(semanticModel, left, cancellationToken)) + { + return true; + } + } + } + + return false; + } + + private bool IsArgumentToAttributeParameterWithMatchingStringSyntaxAttribute( + SemanticModel semanticModel, SyntaxNode argument, CancellationToken cancellationToken, out TOptions options) + { + var parameter = Info.SemanticFacts.FindParameterForAttributeArgument(semanticModel, argument, cancellationToken); + return IsParameterWithMatchingStringSyntaxAttribute(semanticModel, argument, parameter, cancellationToken, out options); + } + + private bool IsArgumentToParameterWithMatchingStringSyntaxAttribute(SemanticModel semanticModel, SyntaxNode argument, CancellationToken cancellationToken, out TOptions options) + { + var parameter = Info.SemanticFacts.FindParameterForArgument(semanticModel, argument, cancellationToken); + return IsParameterWithMatchingStringSyntaxAttribute(semanticModel, argument, parameter, cancellationToken, out options); + } + + private bool IsParameterWithMatchingStringSyntaxAttribute(SemanticModel semanticModel, SyntaxNode argument, IParameterSymbol parameter, CancellationToken cancellationToken, out TOptions options) + { + if (HasMatchingStringSyntaxAttribute(parameter)) + { + options = GetOptionsFromSiblingArgument(argument, semanticModel, cancellationToken) ?? + GetStringSyntaxDefaultOptions(); + return true; + } + + options = default; + return false; + } + + private bool IsFieldOrPropertyWithMatchingStringSyntaxAttribute( + SemanticModel semanticModel, SyntaxNode left, CancellationToken cancellationToken) + { + var symbol = semanticModel.GetSymbolInfo(left, cancellationToken).Symbol; + return symbol is IFieldSymbol or IPropertySymbol && + HasMatchingStringSyntaxAttribute(symbol); + } + + private bool HasMatchingStringSyntaxAttribute([NotNullWhen(true)] ISymbol? symbol) + { + if (symbol != null) + { + foreach (var attribute in symbol.GetAttributes()) + { + if (IsMatchingStringSyntaxAttribute(attribute)) + return true; + } + } + + return false; + } + + private bool IsMatchingStringSyntaxAttribute(AttributeData attribute) + { + if (attribute.ConstructorArguments.Length == 0) + return false; + + if (attribute.AttributeClass is not + { + Name: "StringSyntaxAttribute", + ContainingNamespace: + { + Name: nameof(CodeAnalysis), + ContainingNamespace: + { + Name: nameof(Diagnostics), + ContainingNamespace: + { + Name: nameof(System), + ContainingNamespace.IsGlobalNamespace: true, + } + } + } + }) + { + return false; + } + + var argument = attribute.ConstructorArguments[0]; + return argument.Kind == TypedConstantKind.Primitive && argument.Value is string argString && argString == _stringSyntaxAttributeName; + } + + /// + /// Attempts to parse the string-literal-like into an embedded language tree. The + /// token must either be in a location semantically known to accept this language, or it must have an + /// appropriate comment on it stating that it should be interpreted as this language. + /// + public TTree? TryParseString(SyntaxToken token, SemanticModel semanticModel, CancellationToken cancellationToken) + { + if (!this.IsEmbeddedLanguageToken(token, semanticModel, cancellationToken, out var options)) + return null; + + var chars = Info.VirtualCharService.TryConvertToVirtualChars(token); + return TryParse(chars, options); + } + + protected TOptions? GetOptionsFromSiblingArgument( + SyntaxNode argument, + SemanticModel semanticModel, + CancellationToken cancellationToken) + { + var syntaxFacts = Info.SyntaxFacts; + var argumentList = argument.GetRequiredParent(); + var arguments = syntaxFacts.IsArgument(argument) + ? syntaxFacts.GetArgumentsOfArgumentList(argumentList) + : syntaxFacts.GetArgumentsOfAttributeArgumentList(argumentList); + foreach (var siblingArg in arguments) + { + if (siblingArg != argument) + { + var expr = syntaxFacts.IsArgument(argument) + ? syntaxFacts.GetExpressionOfArgument(siblingArg) + : syntaxFacts.GetExpressionOfAttributeArgument(siblingArg); + if (expr != null) + { + var exprType = semanticModel.GetTypeInfo(expr, cancellationToken); + if (exprType.Type != null && + TryGetOptions(semanticModel, exprType.Type, expr, cancellationToken, out var options)) + { + return options; + } + } + } + } + + return null; + } + + protected string? GetNameOfType(SyntaxNode? typeNode, ISyntaxFacts syntaxFacts) + { + if (syntaxFacts.IsQualifiedName(typeNode)) + { + return GetNameOfType(syntaxFacts.GetRightSideOfDot(typeNode), syntaxFacts); + } + else if (syntaxFacts.IsIdentifierName(typeNode)) + { + return syntaxFacts.GetIdentifierOfSimpleName(typeNode).ValueText; + } + + return null; + } + + protected string? GetNameOfInvokedExpression(SyntaxNode invokedExpression) + { + var syntaxFacts = Info.SyntaxFacts; + if (syntaxFacts.IsSimpleMemberAccessExpression(invokedExpression)) + { + return syntaxFacts.GetIdentifierOfSimpleName(syntaxFacts.GetNameOfMemberAccessExpression(invokedExpression)).ValueText; + } + else if (syntaxFacts.IsIdentifierName(invokedExpression)) + { + return syntaxFacts.GetIdentifierOfSimpleName(invokedExpression).ValueText; + } + + return null; + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeOptions.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeOptions.cs new file mode 100644 index 0000000000000..110e786332809 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeOptions.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.Features.EmbeddedLanguages.DateAndTime +{ + /// + /// No actual options for DateAndTime. But we use this to fit into the common pattern of embedded languages. + /// + internal enum DateAndTimeOptions + { + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateTimeTree.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateTimeTree.cs new file mode 100644 index 0000000000000..8bd799bea183a --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateTimeTree.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime +{ + /// + /// No actual tree for DateAndTime. But we use this to fit into the common pattern of embedded languages. + /// + internal class DateTimeTree + { + public static readonly DateTimeTree Instance = new(); + + private DateTimeTree() + { + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs index 3d73f905809e3..2993b0877c06b 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification.Classifiers; using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime.LanguageServices; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -23,22 +24,17 @@ public DateAndTimeEmbeddedLanguage(EmbeddedLanguageInfo info) Info = info; } - internal async Task TryGetDateAndTimeTokenAtPositionAsync( + public async Task TryGetDateAndTimeTokenAtPositionAsync( Document document, int position, CancellationToken cancellationToken) { var syntaxFacts = document.GetRequiredLanguageService(); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = GetToken(syntaxFacts, root, position); - if (!DateAndTimePatternDetector.IsPossiblyDateAndTimeArgumentToken(token, syntaxFacts, out _, out _) && - token.RawKind != syntaxFacts.SyntaxKinds.InterpolatedStringTextToken) - { - return null; - } var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var detector = DateAndTimePatternDetector.TryGetOrCreate(semanticModel, this.Info); - return detector != null && detector.IsDateAndTimeToken(token, syntaxFacts, cancellationToken) + var detector = DateAndTimeLanguageDetector.GetOrCreate(semanticModel.Compilation, this.Info); + return detector.TryParseString(token, semanticModel, cancellationToken) != null ? token : null; } diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeLanguageDetector.cs new file mode 100644 index 0000000000000..715f3875ba89c --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeLanguageDetector.cs @@ -0,0 +1,202 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime.LanguageServices +{ + /// + /// Helper class to detect and format + /// strings in a document efficiently. + /// + internal sealed class DateAndTimeLanguageDetector : AbstractLanguageDetector + { + private const string FormatName = "format"; + + /// + /// Cache so that we can reuse the same when analyzing a particular + /// semantic model. This saves the time from having to recreate this for every string literal that features + /// examine for a particular compilation. + /// + private static readonly ConditionalWeakTable s_compilationToDetector = new(); + + /// + /// Helps match patterns of the form: language=date (or `time` or `datetime`) + /// + /// All matching is case insensitive. + /// + private static readonly LanguageCommentDetector s_languageCommentDetector = new("date", "time", "datetime"); + + private readonly INamedTypeSymbol? _dateTimeType; + private readonly INamedTypeSymbol? _dateTimeOffsetType; + + public DateAndTimeLanguageDetector( + EmbeddedLanguageInfo info, + INamedTypeSymbol? dateTimeType, + INamedTypeSymbol? dateTimeOffsetType) + : base("DateTimeFormat", info, s_languageCommentDetector) + { + _dateTimeType = dateTimeType; + _dateTimeOffsetType = dateTimeOffsetType; + } + + protected override bool TryGetOptions(SemanticModel semanticModel, ITypeSymbol exprType, SyntaxNode expr, CancellationToken cancellationToken, out DateAndTimeOptions options) + { + // DateTime never has any options. So just return empty and 'true' so we stop processing immediately. + options = default; + return true; + } + + protected override DateTimeTree? TryParse(VirtualCharSequence chars, DateAndTimeOptions options) + { + // Once we've determined something is a DateTime string, then parsing is a no-op. We just return a dummy + // instance to satisfy the detector requirements. + return DateTimeTree.Instance; + } + + public static DateAndTimeLanguageDetector GetOrCreate( + Compilation compilation, EmbeddedLanguageInfo info) + { + // Do a quick non-allocating check first. + if (s_compilationToDetector.TryGetValue(compilation, out var detector)) + return detector; + + return s_compilationToDetector.GetValue(compilation, _ => Create(compilation, info)); + } + + private static DateAndTimeLanguageDetector Create( + Compilation compilation, EmbeddedLanguageInfo info) + { + var dateTimeType = compilation.GetTypeByMetadataName(typeof(DateTime).FullName!); + var dateTimeOffsetType = compilation.GetTypeByMetadataName(typeof(DateTimeOffset).FullName!); + + return new DateAndTimeLanguageDetector(info, dateTimeType, dateTimeOffsetType); + } + + protected override bool IsEmbeddedLanguageInterpolatedStringTextToken(SyntaxToken token, SemanticModel semanticModel, CancellationToken cancellationToken) + { + var syntaxFacts = Info.SyntaxFacts; + var interpolationFormatClause = token.Parent; + var interpolation = interpolationFormatClause?.Parent; + if (interpolation?.RawKind != syntaxFacts.SyntaxKinds.Interpolation) + return false; + + var expression = syntaxFacts.GetExpressionOfInterpolation(interpolation); + var type = semanticModel.GetTypeInfo(expression, cancellationToken).Type; + return IsDateTimeType(type); + } + + protected override bool IsArgumentToWellKnownAPI( + SyntaxToken token, + SyntaxNode argumentNode, + SemanticModel semanticModel, + CancellationToken cancellationToken, + out DateAndTimeOptions options) + { + options = default; + + var argumentList = argumentNode.Parent; + var invocationOrCreation = argumentList?.Parent; + + var syntaxFacts = Info.SyntaxFacts; + if (!syntaxFacts.IsInvocationExpression(invocationOrCreation)) + return false; + + var invokedExpression = syntaxFacts.GetExpressionOfInvocationExpression(invocationOrCreation); + var name = GetNameOfInvokedExpression(syntaxFacts, invokedExpression); + if (name is not nameof(ToString) and not nameof(DateTime.ParseExact) and not nameof(DateTime.TryParseExact)) + return false; + + // We have a string literal passed to a method called ToString/ParseExact/TryParseExact. + // Have to do a more expensive semantic check now. + + // if we couldn't determine the arg name or arg index, can't proceed. + var (argName, argIndex) = GetArgumentNameOrIndex(argumentNode); + if (argName == null && argIndex == null) + return false; + + // If we had a specified arg name and it isn't 'format', then it's not a DateTime + // 'format' param we care about. + if (argName is not null and not FormatName) + return false; + + var symbolInfo = semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken); + var method = symbolInfo.Symbol; + if (TryAnalyzeInvocation(method, argName, argIndex)) + return true; + + foreach (var candidate in symbolInfo.CandidateSymbols) + { + if (TryAnalyzeInvocation(candidate, argName, argIndex)) + return true; + } + + return true; + } + + private static string? GetNameOfInvokedExpression(ISyntaxFacts syntaxFacts, SyntaxNode invokedExpression) + { + if (syntaxFacts.IsSimpleMemberAccessExpression(invokedExpression)) + return syntaxFacts.GetIdentifierOfSimpleName(syntaxFacts.GetNameOfMemberAccessExpression(invokedExpression)).ValueText; + + if (syntaxFacts.IsMemberBindingExpression(invokedExpression)) + invokedExpression = syntaxFacts.GetNameOfMemberBindingExpression(invokedExpression); + + if (syntaxFacts.IsIdentifierName(invokedExpression)) + return syntaxFacts.GetIdentifierOfSimpleName(invokedExpression).ValueText; + + return null; + } + + private static bool IsMethodArgument(SyntaxToken token, ISyntaxFacts syntaxFacts) + => syntaxFacts.IsLiteralExpression(token.Parent) && + syntaxFacts.IsArgument(token.Parent!.Parent); + + private (string? name, int? index) GetArgumentNameOrIndex(SyntaxNode argument) + { + var syntaxFacts = Info.SyntaxFacts; + + var argName = syntaxFacts.GetNameForArgument(argument); + if (argName != "") + return (argName, null); + + var arguments = syntaxFacts.GetArgumentsOfArgumentList(argument.GetRequiredParent()); + var index = arguments.IndexOf(argument); + if (index >= 0) + return (null, index); + + return default; + } + + private bool TryAnalyzeInvocation(ISymbol? symbol, string? argName, int? argIndex) + => symbol is IMethodSymbol method && + method.DeclaredAccessibility == Accessibility.Public && + method.MethodKind == MethodKind.Ordinary && + IsDateTimeType(method.ContainingType) && + AnalyzeStringLiteral(method, argName, argIndex); + + private bool IsDateTimeType(ITypeSymbol? type) + => type != null && (type.Equals(_dateTimeType) || type.Equals(_dateTimeOffsetType)); + + private static bool AnalyzeStringLiteral(IMethodSymbol method, string? argName, int? argIndex) + { + Debug.Assert(argName != null || argIndex != null); + + var parameters = method.Parameters; + if (argName != null) + return parameters.Any(p => p.Name == argName); + + var parameter = argIndex < parameters.Length ? parameters[argIndex.Value] : null; + return parameter?.Name == FormatName; + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimePatternDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimePatternDetector.cs deleted file mode 100644 index ba79021a93ac0..0000000000000 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimePatternDetector.cs +++ /dev/null @@ -1,216 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading; -using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; -using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.EmbeddedLanguages.DateAndTime.LanguageServices -{ - /// - /// Helper class to detect and format - /// strings in a document efficiently. - /// - internal sealed class DateAndTimePatternDetector - { - private const string FormatName = "format"; - - /// - /// Cache so that we can reuse the same when analyzing a particular - /// semantic model. This saves the time from having to recreate this for every string literal that features - /// examine for a particular semantic model. - /// - private static readonly ConditionalWeakTable _modelToDetector = - new(); - - private readonly EmbeddedLanguageInfo _info; - private readonly SemanticModel _semanticModel; - private readonly INamedTypeSymbol _dateTimeType; - private readonly INamedTypeSymbol _dateTimeOffsetType; - - public DateAndTimePatternDetector( - SemanticModel semanticModel, - EmbeddedLanguageInfo info, - INamedTypeSymbol dateTimeType, - INamedTypeSymbol dateTimeOffsetType) - { - _info = info; - _semanticModel = semanticModel; - _dateTimeType = dateTimeType; - _dateTimeOffsetType = dateTimeOffsetType; - } - - public static DateAndTimePatternDetector? TryGetOrCreate( - SemanticModel semanticModel, EmbeddedLanguageInfo info) - { - // Do a quick non-allocating check first. - if (_modelToDetector.TryGetValue(semanticModel, out var detector)) - { - return detector; - } - - return _modelToDetector.GetValue( - semanticModel, _ => TryCreate(semanticModel, info)); - } - - private static DateAndTimePatternDetector? TryCreate( - SemanticModel semanticModel, EmbeddedLanguageInfo info) - { - var dateTimeType = semanticModel.Compilation.GetTypeByMetadataName(typeof(System.DateTime).FullName!); - var dateTimeOffsetType = semanticModel.Compilation.GetTypeByMetadataName(typeof(System.DateTimeOffset).FullName!); - if (dateTimeType == null || dateTimeOffsetType == null) - return null; - - return new DateAndTimePatternDetector(semanticModel, info, dateTimeType, dateTimeOffsetType); - } - - /// - /// Checks if this is possibly a string literal token that could contain a date or time - /// format string passed into an method call. If so, and will be the argument and invocatoin the string literal was passed as. - /// - public static bool IsPossiblyDateAndTimeArgumentToken( - SyntaxToken token, ISyntaxFacts syntaxFacts, - [NotNullWhen(true)] out SyntaxNode? argumentNode, - [NotNullWhen(true)] out SyntaxNode? invocationExpression) - { - // Has to be a string literal passed to a method. - argumentNode = null; - invocationExpression = null; - - if (!syntaxFacts.IsStringLiteral(token)) - return false; - - if (!IsMethodArgument(token, syntaxFacts)) - return false; - - if (!syntaxFacts.IsLiteralExpression(token.Parent)) - return false; - - if (!syntaxFacts.IsArgument(token.Parent.Parent)) - return false; - - var argumentList = token.Parent.Parent.Parent; - var invocationOrCreation = argumentList?.Parent; - if (!syntaxFacts.IsInvocationExpression(invocationOrCreation)) - return false; - - var invokedExpression = syntaxFacts.GetExpressionOfInvocationExpression(invocationOrCreation); - var name = GetNameOfInvokedExpression(syntaxFacts, invokedExpression); - if (name is not nameof(ToString) and not nameof(DateTime.ParseExact) and not nameof(DateTime.TryParseExact)) - return false; - - // We have a string literal passed to a method called ToString/ParseExact/TryParseExact. - // Have to do a more expensive semantic check now. - argumentNode = token.Parent.Parent; - invocationExpression = invocationOrCreation; - - return true; - } - - private static string? GetNameOfInvokedExpression(ISyntaxFacts syntaxFacts, SyntaxNode invokedExpression) - { - if (syntaxFacts.IsSimpleMemberAccessExpression(invokedExpression)) - return syntaxFacts.GetIdentifierOfSimpleName(syntaxFacts.GetNameOfMemberAccessExpression(invokedExpression)).ValueText; - - if (syntaxFacts.IsMemberBindingExpression(invokedExpression)) - invokedExpression = syntaxFacts.GetNameOfMemberBindingExpression(invokedExpression); - - if (syntaxFacts.IsIdentifierName(invokedExpression)) - return syntaxFacts.GetIdentifierOfSimpleName(invokedExpression).ValueText; - - return null; - } - - private static bool IsMethodArgument(SyntaxToken token, ISyntaxFacts syntaxFacts) - => syntaxFacts.IsLiteralExpression(token.Parent) && - syntaxFacts.IsArgument(token.Parent!.Parent); - - public bool IsDateAndTimeToken(SyntaxToken token, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken) - { - if (IsPossiblyDateAndTimeArgumentToken( - token, _info.SyntaxFacts, - out var argumentNode, out var invocationOrCreation)) - { - // if we couldn't determine the arg name or arg index, can't proceed. - var (argName, argIndex) = GetArgumentNameOrIndex(argumentNode); - if (argName == null && argIndex == null) - return false; - - // If we had a specified arg name and it isn't 'format', then it's not a DateTime - // 'format' param we care about. - if (argName is not null and not FormatName) - return false; - - var symbolInfo = _semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken); - var method = symbolInfo.Symbol; - if (TryAnalyzeInvocation(method, argName, argIndex)) - return true; - - foreach (var candidate in symbolInfo.CandidateSymbols) - { - if (TryAnalyzeInvocation(candidate, argName, argIndex)) - return true; - } - } - else if (token.RawKind == syntaxFacts.SyntaxKinds.InterpolatedStringTextToken) - { - var interpolationFormatClause = token.Parent!; - var interpolation = interpolationFormatClause.Parent!; - if (interpolation.RawKind == syntaxFacts.SyntaxKinds.Interpolation) - { - var expression = syntaxFacts.GetExpressionOfInterpolation(interpolation)!; - var type = _semanticModel.GetTypeInfo(expression, cancellationToken).Type; - return IsDateTimeType(type); - } - } - - return false; - } - - private (string? name, int? index) GetArgumentNameOrIndex(SyntaxNode argument) - { - var syntaxFacts = _info.SyntaxFacts; - - var argName = syntaxFacts.GetNameForArgument(argument); - if (argName != "") - return (argName, null); - - var arguments = syntaxFacts.GetArgumentsOfArgumentList(argument.GetRequiredParent()); - var index = arguments.IndexOf(argument); - if (index >= 0) - return (null, index); - - return default; - } - - private bool TryAnalyzeInvocation(ISymbol? symbol, string? argName, int? argIndex) - => symbol is IMethodSymbol method && - method.DeclaredAccessibility == Accessibility.Public && - method.MethodKind == MethodKind.Ordinary && - IsDateTimeType(method.ContainingType) && - AnalyzeStringLiteral(method, argName, argIndex); - - private bool IsDateTimeType(ITypeSymbol? type) - => _dateTimeType.Equals(type) || _dateTimeOffsetType.Equals(type); - - private static bool AnalyzeStringLiteral(IMethodSymbol method, string? argName, int? argIndex) - { - Debug.Assert(argName != null || argIndex != null); - - var parameters = method.Parameters; - if (argName != null) - return parameters.Any(p => p.Name == argName); - - var parameter = argIndex < parameters.Length ? parameters[argIndex.Value] : null; - return parameter?.Name == FormatName; - } - } -} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/IEmbeddedLanguageFeatures.cs b/src/Features/Core/Portable/EmbeddedLanguages/IEmbeddedLanguageFeatures.cs index e847cbc680023..6752db9105a7e 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/IEmbeddedLanguageFeatures.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/IEmbeddedLanguageFeatures.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.DocumentHighlighting; using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; @@ -27,6 +26,6 @@ internal interface IEmbeddedLanguageFeatures : IEmbeddedLanguage /// individual providers and expose them as one single completion provider to /// the rest of Roslyn. /// - EmbeddedLanguageCompletionProvider CompletionProvider { get; } + EmbeddedLanguageCompletionProvider? CompletionProvider { get; } } } diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/IJsonNodeVisitor.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/IJsonNodeVisitor.cs new file mode 100644 index 0000000000000..113d28887119d --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/IJsonNodeVisitor.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + internal interface IJsonNodeVisitor + { + void Visit(JsonCompilationUnit node); + void Visit(JsonArrayNode node); + void Visit(JsonObjectNode node); + void Visit(JsonPropertyNode node); + void Visit(JsonConstructorNode node); + void Visit(JsonLiteralNode node); + void Visit(JsonNegativeLiteralNode node); + void Visit(JsonTextNode node); + void Visit(JsonCommaValueNode node); + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonHelpers.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonHelpers.cs new file mode 100644 index 0000000000000..c39b1734ca1ea --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonHelpers.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + using JsonToken = EmbeddedSyntaxToken; + using JsonTrivia = EmbeddedSyntaxTrivia; + + internal static class JsonHelpers + { + public static JsonToken CreateToken( + JsonKind kind, ImmutableArray leadingTrivia, + VirtualCharSequence virtualChars, ImmutableArray trailingTrivia) + => CreateToken(kind, leadingTrivia, virtualChars, trailingTrivia, ImmutableArray.Empty); + + public static JsonToken CreateToken(JsonKind kind, + ImmutableArray leadingTrivia, VirtualCharSequence virtualChars, + ImmutableArray trailingTrivia, ImmutableArray diagnostics) + => new(kind, leadingTrivia, virtualChars, trailingTrivia, diagnostics, value: null!); + + public static JsonToken CreateMissingToken(JsonKind kind) + => CreateToken(kind, ImmutableArray.Empty, VirtualCharSequence.Empty, ImmutableArray.Empty); + + public static JsonTrivia CreateTrivia(JsonKind kind, VirtualCharSequence virtualChars) + => CreateTrivia(kind, virtualChars, ImmutableArray.Empty); + + public static JsonTrivia CreateTrivia(JsonKind kind, VirtualCharSequence virtualChars, EmbeddedDiagnostic diagnostic) + => CreateTrivia(kind, virtualChars, ImmutableArray.Create(diagnostic)); + + public static JsonTrivia CreateTrivia(JsonKind kind, VirtualCharSequence virtualChars, ImmutableArray diagnostics) + => new(kind, virtualChars, diagnostics); + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonKind.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonKind.cs new file mode 100644 index 0000000000000..ecec5f5b57788 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonKind.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + internal enum JsonKind + { + None = 0, + + // Nodes + CompilationUnit, + Text, + Object, + Array, + Literal, + // Used to represent `-Infinity` which is supported by Json.Net + NegativeLiteral, + Property, + Constructor, + CommaValue, + + // Tokens + EndOfFile, + OpenBraceToken, + CloseBraceToken, + OpenBracketToken, + CloseBracketToken, + OpenParenToken, + CloseParenToken, + StringToken, + NumberToken, + TextToken, + ColonToken, + CommaToken, + TrueLiteralToken, + FalseLiteralToken, + NullLiteralToken, + UndefinedLiteralToken, + NaNLiteralToken, + InfinityLiteralToken, + NegativeInfinityLiteralToken, + MinusToken, + NewKeyword, + + // Trivia + SingleLineCommentTrivia, + MultiLineCommentTrivia, + WhitespaceTrivia, + EndOfLineTrivia, + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonLexer.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonLexer.cs new file mode 100644 index 0000000000000..20041f30c541c --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonLexer.cs @@ -0,0 +1,346 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Diagnostics; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + using static EmbeddedSyntaxHelpers; + using static JsonHelpers; + + using JsonToken = EmbeddedSyntaxToken; + using JsonTrivia = EmbeddedSyntaxTrivia; + + [NonCopyable] + internal struct JsonLexer + { + public readonly VirtualCharSequence Text; + public int Position; + + public JsonLexer(VirtualCharSequence text) : this() + { + Text = text; + } + + public VirtualChar CurrentChar => Text[Position]; + + public VirtualCharSequence GetCharsToCurrentPosition(int start) + => GetSubSequence(start, Position); + + public VirtualCharSequence GetSubSequence(int start, int end) + => Text.GetSubSequence(TextSpan.FromBounds(start, end)); + + public JsonToken ScanNextToken() + { + var leadingTrivia = ScanTrivia(leading: true); + if (Position == Text.Length) + { + return CreateToken( + JsonKind.EndOfFile, leadingTrivia, + VirtualCharSequence.Empty, ImmutableArray.Empty); + } + + var (chars, kind, diagnostic) = ScanNextTokenWorker(); + Debug.Assert(chars.Length > 0); + + var trailingTrivia = ScanTrivia(leading: false); + var token = CreateToken(kind, leadingTrivia, chars, trailingTrivia); + + return diagnostic == null + ? token + : token.AddDiagnosticIfNone(diagnostic.Value); + } + + private (VirtualCharSequence, JsonKind, EmbeddedDiagnostic? diagnostic) ScanNextTokenWorker() + { + Debug.Assert(Position < Text.Length); + return this.CurrentChar.Value switch + { + '{' => ScanSingleCharToken(JsonKind.OpenBraceToken), + '}' => ScanSingleCharToken(JsonKind.CloseBraceToken), + '[' => ScanSingleCharToken(JsonKind.OpenBracketToken), + ']' => ScanSingleCharToken(JsonKind.CloseBracketToken), + '(' => ScanSingleCharToken(JsonKind.OpenParenToken), + ')' => ScanSingleCharToken(JsonKind.CloseParenToken), + ',' => ScanSingleCharToken(JsonKind.CommaToken), + ':' => ScanSingleCharToken(JsonKind.ColonToken), + '\'' or '"' => ScanString(), + // It would be tempting to try to scan out numbers here. However, numbers are + // actually quite tricky to get right (especially looking one character at a time). + // So, instead, we take a page from json.net and just consume out a text sequence. + // Later on, we'll analyze that text sequence as a whole to see if it looks like a + // number and to also report any issues in line with how json.net and ecmascript + // handle json numbers. + _ => ScanText(), + }; + } + + private (VirtualCharSequence, JsonKind, EmbeddedDiagnostic?) ScanString() + { + var start = Position; + var openChar = this.CurrentChar; + Position++; + + EmbeddedDiagnostic? diagnostic = null; + while (Position < Text.Length) + { + var currentCh = this.CurrentChar; + + Position++; + switch (currentCh.Value) + { + case '"': + case '\'': + if (currentCh.Value == openChar.Value) + return (GetCharsToCurrentPosition(start), JsonKind.StringToken, diagnostic); + + continue; + + case '\\': + var escapeDiag = AdvanceToEndOfEscape(start, escapeStart: Position - 1); + diagnostic ??= escapeDiag; + continue; + } + } + + var chars = GetCharsToCurrentPosition(start); + diagnostic ??= new EmbeddedDiagnostic( + FeaturesResources.Unterminated_string, GetSpan(chars)); + return (chars, JsonKind.StringToken, diagnostic); + } + + /// + /// does not actually lex out an escape token. Instead, it just moves the + /// position forward and returns a diagnostic if this was not a valid escape. + /// + private EmbeddedDiagnostic? AdvanceToEndOfEscape(int stringStart, int escapeStart) + { + if (this.Position == Text.Length) + { + var chars = GetCharsToCurrentPosition(stringStart); + return new EmbeddedDiagnostic(FeaturesResources.Unterminated_string, GetSpan(chars)); + } + + var currentCh = this.CurrentChar; + Position++; + + return currentCh.Value switch + { + 'b' or 't' or 'n' or 'f' or 'r' or '\\' or '"' or '\'' or '/' => null, + 'u' => ScanUnicodeChars(escapeStart, Position), + _ => new EmbeddedDiagnostic(FeaturesResources.Invalid_escape_sequence, GetSpan(GetCharsToCurrentPosition(escapeStart))), + }; + } + + private EmbeddedDiagnostic? ScanUnicodeChars(int escapeStart, int unicodeCharStart) + { + var invalid = false; + for (var i = 0; this.Position < Text.Length && i < 4; i++) + { + var ch = this.CurrentChar; + Position++; + + invalid |= !IsHexDigit(ch); + } + + if (invalid || (Position - unicodeCharStart != 4)) + { + var chars = GetCharsToCurrentPosition(escapeStart); + return new EmbeddedDiagnostic(FeaturesResources.Invalid_escape_sequence, GetSpan(chars)); + } + + return null; + } + + private static bool IsHexDigit(VirtualChar c) + => c.Value is (>= '0' and <= '9') or + (>= 'A' and <= 'F') or + (>= 'a' and <= 'f'); + + private (VirtualCharSequence, JsonKind, EmbeddedDiagnostic?) ScanText() + { + var start = Position; + + while (Position < Text.Length && !IsNotPartOfText(this.CurrentChar)) + Position++; + + return (GetCharsToCurrentPosition(start), JsonKind.TextToken, null); + + static bool IsNotPartOfText(VirtualChar ch) + => ch.Value switch + { + // Standard tokens. + '{' or '}' or '[' or ']' or '(' or ')' or ',' or ':' or '\'' or '"' => true, + // trivia cases + ' ' or '\t' or '/' or '\r' or '\n' => true, + // more trivia + _ => ch.IsWhiteSpace, + }; + } + + private (VirtualCharSequence, JsonKind, EmbeddedDiagnostic?) ScanSingleCharToken(JsonKind kind) + { + var chars = this.Text.GetSubSequence(new TextSpan(Position, 1)); + Position++; + return (chars, kind, null); + } + + private ImmutableArray ScanTrivia(bool leading) + { + using var _ = ArrayBuilder.GetInstance(out var result); + + while (Position < Text.Length) + { + var comment = ScanComment(); + if (comment != null) + { + result.Add(comment.Value); + continue; + } + + var endOfLine = ScanEndOfLine(); + if (endOfLine != null) + { + result.Add(endOfLine.Value); + + if (leading) + { + continue; + } + else + { + break; + } + } + + var whitespace = ScanWhitespace(); + if (whitespace != null) + { + result.Add(whitespace.Value); + continue; + } + + break; + } + + return result.ToImmutable(); + } + + private JsonTrivia? ScanEndOfLine() + { + var start = Position; + if (IsAt("\r\n")) + { + Position += 2; + return CreateTrivia(JsonKind.EndOfLineTrivia, GetCharsToCurrentPosition(start)); + } + else if (IsAt("\r") || IsAt("\n")) + { + Position++; + return CreateTrivia(JsonKind.EndOfLineTrivia, GetCharsToCurrentPosition(start)); + } + + return null; + } + + public JsonTrivia? ScanComment() + { + if (IsAt("//")) + { + return ScanSingleLineComment(); + } + else if (IsAt("/*")) + { + return ScanMultiLineComment(); + } + else if (IsAt("/")) + { + var start = Position; + Position++; + + var chars = GetCharsToCurrentPosition(start); + return CreateTrivia(JsonKind.SingleLineCommentTrivia, chars, + new EmbeddedDiagnostic(FeaturesResources.Error_parsing_comment, GetSpan(chars))); + } + + return null; + } + + private JsonTrivia ScanSingleLineComment() + { + Debug.Assert(IsAt("//")); + var start = Position; + Position += 2; + + while (Position < Text.Length && this.CurrentChar.Value is not '\r' and not '\n') + Position++; + + var chars = GetCharsToCurrentPosition(start); + if (Position == start + 2) + { + // Note: json.net reports an error if the file ends with "//", so we just + // preserve that behavior. + return CreateTrivia(JsonKind.SingleLineCommentTrivia, chars, + new EmbeddedDiagnostic(FeaturesResources.Unterminated_comment, GetSpan(chars))); + } + + return CreateTrivia(JsonKind.SingleLineCommentTrivia, chars); + } + + private JsonTrivia ScanMultiLineComment() + { + Debug.Assert(IsAt("/*")); + var start = Position; + Position += 2; + + while (Position < Text.Length && !IsAt("*/")) + Position++; + + if (IsAt("*/")) + { + Position += 2; + return CreateTrivia(JsonKind.MultiLineCommentTrivia, GetCharsToCurrentPosition(start)); + } + + Debug.Assert(Position == Text.Length); + return CreateTrivia(JsonKind.MultiLineCommentTrivia, GetCharsToCurrentPosition(start), + new EmbeddedDiagnostic(FeaturesResources.Unterminated_comment, GetTextSpan(start, Position))); + } + + private TextSpan GetTextSpan(int startInclusive, int endExclusive) + => TextSpan.FromBounds(Text[startInclusive].Span.Start, Text[endExclusive - 1].Span.End); + + private bool IsAt(string val) + => TextAt(this.Position, val); + + private bool TextAt(int position, string val) + { + for (var i = 0; i < val.Length; i++) + { + if (position + i >= Text.Length || Text[position + i] != val[i]) + return false; + } + + return true; + } + + private JsonTrivia? ScanWhitespace() + { + var start = Position; + while (Position < Text.Length && this.CurrentChar.IsWhiteSpace) + Position++; + + if (Position > start) + return CreateTrivia(JsonKind.WhitespaceTrivia, GetCharsToCurrentPosition(start)); + + return null; + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonNode.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonNode.cs new file mode 100644 index 0000000000000..4e5c79a39cddc --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonNode.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 Microsoft.CodeAnalysis.EmbeddedLanguages.Common; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + internal abstract class JsonNode : EmbeddedSyntaxNode + { + protected JsonNode(JsonKind kind) : base(kind) + { + } + + public abstract void Accept(IJsonNodeVisitor visitor); + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonNodes.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonNodes.cs new file mode 100644 index 0000000000000..12c29bb81a3c3 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonNodes.cs @@ -0,0 +1,326 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + using JsonNodeOrToken = EmbeddedSyntaxNodeOrToken; + using JsonToken = EmbeddedSyntaxToken; + using JsonSeparatedList = EmbeddedSeparatedSyntaxNodeList; + + internal sealed class JsonCompilationUnit : JsonNode + { + public JsonCompilationUnit(ImmutableArray sequence, JsonToken endOfFileToken) + : base(JsonKind.CompilationUnit) + { + Debug.Assert(sequence != null); + Debug.Assert(endOfFileToken.Kind == JsonKind.EndOfFile); + Sequence = sequence; + EndOfFileToken = endOfFileToken; + } + + /// + /// For error recovery purposes, we support a sequence of nodes at the top level (even + /// though only a single node is actually allowed). + /// + public ImmutableArray Sequence { get; } + public JsonToken EndOfFileToken { get; } + + internal override int ChildCount => Sequence.Length + 1; + + internal override JsonNodeOrToken ChildAt(int index) + { + if (index == Sequence.Length) + return EndOfFileToken; + + return Sequence[index]; + } + + public override void Accept(IJsonNodeVisitor visitor) + => visitor.Visit(this); + } + + /// + /// Root of all value nodes. + /// + internal abstract class JsonValueNode : JsonNode + { + protected JsonValueNode(JsonKind kind) + : base(kind) + { + } + } + + /// + /// Represents a chunk of text that we did not understand as anything special. i.e. it wasn't a keyword, number, or + /// literal. One common case of this is an unquoted property name (which json.net accepts). + /// + internal sealed class JsonTextNode : JsonValueNode + { + public JsonTextNode(JsonToken textToken) + : base(JsonKind.Text) + { + Debug.Assert(textToken.Kind == JsonKind.TextToken); + TextToken = textToken; + } + + public JsonToken TextToken { get; } + + internal override int ChildCount => 1; + + internal override JsonNodeOrToken ChildAt(int index) + => index switch + { + 0 => TextToken, + _ => throw new InvalidOperationException(), + }; + + public override void Accept(IJsonNodeVisitor visitor) + => visitor.Visit(this); + } + + internal sealed class JsonObjectNode : JsonValueNode + { + public JsonObjectNode( + JsonToken openBraceToken, + JsonSeparatedList sequence, + JsonToken closeBraceToken) + : base(JsonKind.Object) + { + Debug.Assert(openBraceToken.Kind == JsonKind.OpenBraceToken); + Debug.Assert(closeBraceToken.Kind == JsonKind.CloseBraceToken); + + OpenBraceToken = openBraceToken; + Sequence = sequence; + CloseBraceToken = closeBraceToken; + } + + public JsonToken OpenBraceToken { get; } + public JsonSeparatedList Sequence { get; } + public JsonToken CloseBraceToken { get; } + + internal override int ChildCount => 2 + Sequence.NodesAndTokens.Length; + + internal override JsonNodeOrToken ChildAt(int index) + { + if (index == 0) + return OpenBraceToken; + + if (index == Sequence.NodesAndTokens.Length + 1) + return CloseBraceToken; + + return Sequence.NodesAndTokens[index - 1]; + } + + public override void Accept(IJsonNodeVisitor visitor) + => visitor.Visit(this); + } + + internal sealed class JsonArrayNode : JsonValueNode + { + public JsonArrayNode( + JsonToken openBracketToken, + ImmutableArray sequence, + JsonToken closeBracketToken) + : base(JsonKind.Array) + { + Debug.Assert(openBracketToken.Kind == JsonKind.OpenBracketToken); + Debug.Assert(sequence != null); + Debug.Assert(closeBracketToken.Kind == JsonKind.CloseBracketToken); + + OpenBracketToken = openBracketToken; + Sequence = sequence; + CloseBracketToken = closeBracketToken; + } + + public JsonToken OpenBracketToken { get; } + public ImmutableArray Sequence { get; } + public JsonToken CloseBracketToken { get; } + + internal override int ChildCount => 2 + Sequence.Length; + + internal override JsonNodeOrToken ChildAt(int index) + { + if (index == 0) + return OpenBracketToken; + + if (index == Sequence.Length + 1) + return CloseBracketToken; + + return Sequence[index - 1]; + } + + public override void Accept(IJsonNodeVisitor visitor) + => visitor.Visit(this); + } + + internal sealed class JsonNegativeLiteralNode : JsonValueNode + { + public JsonNegativeLiteralNode(JsonToken minusToken, JsonToken literalToken) + : base(JsonKind.NegativeLiteral) + { + Debug.Assert(minusToken.Kind == JsonKind.MinusToken); + MinusToken = minusToken; + LiteralToken = literalToken; + } + + public JsonToken MinusToken { get; } + public JsonToken LiteralToken { get; } + + internal override int ChildCount => 2; + + internal override JsonNodeOrToken ChildAt(int index) + => index switch + { + 0 => MinusToken, + 1 => LiteralToken, + _ => throw new InvalidOperationException(), + }; + + public override void Accept(IJsonNodeVisitor visitor) + => visitor.Visit(this); + } + + internal sealed class JsonLiteralNode : JsonValueNode + { + public JsonLiteralNode(JsonToken literalToken) + : base(JsonKind.Literal) + { + LiteralToken = literalToken; + } + + public JsonToken LiteralToken { get; } + + internal override int ChildCount => 1; + + internal override JsonNodeOrToken ChildAt(int index) + => index switch + { + 0 => LiteralToken, + _ => throw new InvalidOperationException(), + }; + + public override void Accept(IJsonNodeVisitor visitor) + => visitor.Visit(this); + } + + /// + /// See the note in for why commas are stored as values for convenience. + /// + internal sealed class JsonCommaValueNode : JsonValueNode + { + public JsonCommaValueNode(JsonToken commaToken) + : base(JsonKind.CommaValue) + { + Debug.Assert(commaToken.Kind == JsonKind.CommaToken); + CommaToken = commaToken; + } + + public JsonToken CommaToken { get; } + + internal override int ChildCount => 1; + + internal override JsonNodeOrToken ChildAt(int index) + => index switch + { + 0 => CommaToken, + _ => throw new InvalidOperationException(), + }; + + public override void Accept(IJsonNodeVisitor visitor) + => visitor.Visit(this); + } + + internal sealed class JsonPropertyNode : JsonValueNode + { + public JsonPropertyNode(JsonToken nameToken, JsonToken colonToken, JsonValueNode value) + : base(JsonKind.Property) + { + // Note: the name is allowed by json.net to just be a text token, not a string. e.g. `goo: 0` as opposed to + // `"goo": 0`. Strict json does not allow this. + Debug.Assert(nameToken.Kind == JsonKind.StringToken || nameToken.Kind == JsonKind.TextToken); + Debug.Assert(colonToken.Kind == JsonKind.ColonToken); + Debug.Assert(value != null); + NameToken = nameToken; + ColonToken = colonToken; + Value = value; + } + + public JsonToken NameToken { get; } + public JsonToken ColonToken { get; } + public JsonValueNode Value { get; } + + internal override int ChildCount => 3; + + internal override JsonNodeOrToken ChildAt(int index) + => index switch + { + 0 => NameToken, + 1 => ColonToken, + 2 => Value, + _ => throw new InvalidOperationException(), + }; + + public override void Accept(IJsonNodeVisitor visitor) + => visitor.Visit(this); + } + + /// + /// Json.net construction. It allows things like new Date(1, 2, 3). This is not allowed in strict mode. + /// + internal sealed class JsonConstructorNode : JsonValueNode + { + public JsonConstructorNode( + JsonToken newKeyword, + JsonToken nameToken, + JsonToken openParenToken, + ImmutableArray sequence, + JsonToken closeParenToken) + : base(JsonKind.Constructor) + { + Debug.Assert(newKeyword.Kind == JsonKind.NewKeyword); + Debug.Assert(nameToken.Kind == JsonKind.TextToken); + Debug.Assert(openParenToken.Kind == JsonKind.OpenParenToken); + Debug.Assert(sequence != null); + Debug.Assert(closeParenToken.Kind == JsonKind.CloseParenToken); + NewKeyword = newKeyword; + NameToken = nameToken; + OpenParenToken = openParenToken; + Sequence = sequence; + CloseParenToken = closeParenToken; + } + + public JsonToken NewKeyword { get; } + public JsonToken NameToken { get; } + public JsonToken OpenParenToken { get; } + public ImmutableArray Sequence { get; } + public JsonToken CloseParenToken { get; } + + internal override int ChildCount => Sequence.Length + 4; + + internal override JsonNodeOrToken ChildAt(int index) + { + if (index == 0) + return NewKeyword; + + if (index == 1) + return NameToken; + + if (index == 2) + return OpenParenToken; + + if (index == Sequence.Length + 3) + return CloseParenToken; + + return Sequence[index - 3]; + } + + public override void Accept(IJsonNodeVisitor visitor) + => visitor.Visit(this); + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonOptions.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonOptions.cs new file mode 100644 index 0000000000000..d69a01f8a1dad --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonOptions.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json; + +[Flags] +internal enum JsonOptions +{ + /// + /// Parse using loose rules. This is very relaxed and allows lots of features not allowed by standard IETF 8259 + /// (like comments, and trailing commas). This also allows all the additional constructs added by Json.net, like + /// constructors and string that use single-quotes instead of double-quotes. + /// + Loose = 0, + /// + /// Strict IETF 8259 mode. Anything not allowed by that spec is flagged as an error. + /// + Strict = 1, + /// + /// Same as except that comments are allowed as well. Corresponds to new JsonDocumentOptions + /// { CommentHandling = Allow } + /// + Comments = 2 | Strict, + /// + /// Same as except that trailing commas are allowed as well. Corresponds to new + /// JsonDocumentOptions { AllowTrailingCommas = true } + /// + TrailingCommas = 4 | Strict, +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonParser.JsonNetSyntaxChecks.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonParser.JsonNetSyntaxChecks.cs new file mode 100644 index 0000000000000..3dac6adf0d26f --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonParser.JsonNetSyntaxChecks.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.Immutable; +using System.Diagnostics; +using System.Globalization; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + using static EmbeddedSyntaxHelpers; + + using JsonToken = EmbeddedSyntaxToken; + + internal partial struct JsonParser + { + private static class JsonNetSyntaxChecker + { + public static EmbeddedDiagnostic? CheckSyntax(JsonNode node) + { + var diagnostic = node.Kind switch + { + JsonKind.Array => CheckArray((JsonArrayNode)node), + JsonKind.Object => CheckObject((JsonObjectNode)node), + JsonKind.Constructor => CheckConstructor((JsonConstructorNode)node), + JsonKind.Property => CheckProperty((JsonPropertyNode)node), + JsonKind.Literal => CheckLiteral((JsonLiteralNode)node), + JsonKind.NegativeLiteral => CheckNegativeLiteral((JsonNegativeLiteralNode)node), + _ => null, + }; + + return Earliest(diagnostic, CheckChildren(node)); + + static EmbeddedDiagnostic? CheckChildren(JsonNode node) + { + foreach (var child in node) + { + if (child.IsNode) + { + var diagnostic = CheckSyntax(child.Node); + if (diagnostic != null) + return diagnostic; + } + } + + return null; + } + } + + private static EmbeddedDiagnostic? CheckLiteral(JsonLiteralNode node) + => node.LiteralToken.Kind == JsonKind.NumberToken + ? CheckNumber(node.LiteralToken) + : null; + + private static EmbeddedDiagnostic? CheckNegativeLiteral(JsonNegativeLiteralNode node) + => node.LiteralToken.Kind == JsonKind.NumberToken + ? CheckNumber(node.LiteralToken) + : null; + + private static EmbeddedDiagnostic? CheckNumber(JsonToken numberToken) + { + // This code was effectively copied from: + // https://github.com/JamesNK/Newtonsoft.Json/blob/993215529562866719689206e27e413013d4439c/Src/Newtonsoft.Json/JsonTextReader.cs#L1926 + // So as to match Newtonsoft.Json's behavior around number parsing. + var chars = numberToken.VirtualChars; + var firstChar = chars[0]; + + var singleDigit = firstChar.IsDigit && chars.Length == 1; + if (singleDigit) + return null; + + var nonBase10 = + firstChar == '0' && chars.Length > 1 && + chars[1] != '.' && chars[1] != 'e' && chars[1] != 'E'; + + var literalText = numberToken.VirtualChars.CreateString(); + if (nonBase10) + { + Debug.Assert(chars.Length > 1); + var b = chars[1] == 'x' || chars[1] == 'X' ? 16 : 8; + + try + { + Convert.ToInt64(literalText, b); + } + catch (Exception) + { + return new EmbeddedDiagnostic(FeaturesResources.Invalid_number, GetSpan(chars)); + } + } + else if (!double.TryParse( + literalText, NumberStyles.Float, + CultureInfo.InvariantCulture, out _)) + { + return new EmbeddedDiagnostic(FeaturesResources.Invalid_number, GetSpan(chars)); + } + + return null; + } + + private static EmbeddedDiagnostic? CheckArray(JsonArrayNode node) + => CheckCommasBetweenSequenceElements(node.Sequence); + + private static EmbeddedDiagnostic? CheckConstructor(JsonConstructorNode node) + => !IsValidConstructorName(node.NameToken) + ? new EmbeddedDiagnostic(FeaturesResources.Invalid_constructor_name, node.NameToken.GetSpan()) + : CheckCommasBetweenSequenceElements(node.Sequence); + + private static bool IsValidConstructorName(JsonToken nameToken) + { + foreach (var vc in nameToken.VirtualChars) + { + if (!vc.IsLetterOrDigit) + return false; + } + + return true; + } + + private static EmbeddedDiagnostic? CheckCommasBetweenSequenceElements(ImmutableArray sequence) + { + // Json.net allows sequences of commas. But after every non-comma value, you need + // a comma. + for (int i = 0, n = sequence.Length - 1; i < n; i++) + { + var child = sequence[i]; + var nextChild = sequence[i + 1]; + if (child.Kind != JsonKind.CommaValue && nextChild.Kind != JsonKind.CommaValue) + return new EmbeddedDiagnostic(string.Format(FeaturesResources._0_expected, ','), GetFirstToken(nextChild).GetSpan()); + } + + return null; + } + + private static EmbeddedDiagnostic? CheckObject(JsonObjectNode node) + { + foreach (var child in node.Sequence) + { + if (child.Kind != JsonKind.Property) + return new EmbeddedDiagnostic(FeaturesResources.Only_properties_allowed_in_an_object, GetFirstToken(child).GetSpan()); + } + + return null; + } + + private static EmbeddedDiagnostic? CheckProperty(JsonPropertyNode node) + => node.NameToken.Kind != JsonKind.StringToken && !IsLegalPropertyNameText(node.NameToken) + ? new EmbeddedDiagnostic(FeaturesResources.Invalid_property_name, node.NameToken.GetSpan()) + : null; + + private static bool IsLegalPropertyNameText(JsonToken textToken) + { + foreach (var ch in textToken.VirtualChars) + { + if (!IsLegalPropertyNameChar(ch)) + return false; + } + + return true; + } + + private static bool IsLegalPropertyNameChar(VirtualChar ch) + => ch.IsLetterOrDigit || ch == '_' || ch == '$'; + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonParser.StrictSyntaxChecker.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonParser.StrictSyntaxChecker.cs new file mode 100644 index 0000000000000..6f72e685a8234 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonParser.StrictSyntaxChecker.cs @@ -0,0 +1,266 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.Text.RegularExpressions; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + using static EmbeddedSyntaxHelpers; + + using JsonToken = EmbeddedSyntaxToken; + using JsonTrivia = EmbeddedSyntaxTrivia; + + internal partial struct JsonParser + { + /// + /// Checks the superset-tree for constructs that aren't allowed in strict rfc8259 + /// (https://tools.ietf.org/html/rfc8259) mode. + /// + private static class StrictSyntaxChecker + { + public static EmbeddedDiagnostic? CheckRootSyntax(JsonCompilationUnit node, JsonOptions options) + { + var allowComments = options.HasFlag(JsonOptions.Comments); + var allowTrailingCommas = options.HasFlag(JsonOptions.TrailingCommas); + return CheckSyntax(node, allowComments, allowTrailingCommas); + } + + private static EmbeddedDiagnostic? CheckSyntax( + JsonNode node, bool allowComments, bool allowTrailingCommas) + { + var diagnostic = node.Kind switch + { + JsonKind.Constructor => CheckConstructor((JsonConstructorNode)node), + JsonKind.Literal => CheckLiteral((JsonLiteralNode)node, allowComments), + JsonKind.NegativeLiteral => CheckNegativeLiteral((JsonNegativeLiteralNode)node), + JsonKind.Property => CheckProperty((JsonPropertyNode)node, allowComments), + JsonKind.Array => CheckArray((JsonArrayNode)node, allowTrailingCommas), + JsonKind.Object => CheckObject((JsonObjectNode)node, allowTrailingCommas), + _ => null, + }; + + return Earliest(diagnostic, CheckChildren(node)); + + EmbeddedDiagnostic? CheckChildren(JsonNode node) + { + foreach (var child in node) + { + var diagnostic = child.IsNode + ? CheckSyntax(child.Node, allowComments, allowTrailingCommas) + : CheckToken(child.Token, allowComments); + if (diagnostic != null) + return diagnostic; + } + + return null; + } + } + + private static EmbeddedDiagnostic? CheckToken(JsonToken token, bool allowComments) + => CheckTrivia(token.LeadingTrivia, allowComments) ?? CheckTrivia(token.TrailingTrivia, allowComments); + + private static EmbeddedDiagnostic? CheckTrivia( + ImmutableArray triviaList, bool allowComments) + { + foreach (var trivia in triviaList) + { + var diagnostic = CheckTrivia(trivia, allowComments); + if (diagnostic != null) + return diagnostic; + } + + return null; + } + + private static EmbeddedDiagnostic? CheckTrivia(JsonTrivia trivia, bool allowComments) + => trivia.Kind switch + { + // Strict mode doesn't allow comments at all. + JsonKind.MultiLineCommentTrivia or JsonKind.SingleLineCommentTrivia when !allowComments + => new EmbeddedDiagnostic(FeaturesResources.Comments_not_allowed, GetSpan(trivia.VirtualChars)), + JsonKind.WhitespaceTrivia => CheckWhitespace(trivia), + _ => null, + }; + + private static EmbeddedDiagnostic? CheckWhitespace(JsonTrivia trivia) + { + foreach (var ch in trivia.VirtualChars) + { + switch (ch.Value) + { + case ' ': + case '\t': + break; + + default: + // Strict mode only allows spaces and horizontal tabs. Everything else + // is illegal. + return new EmbeddedDiagnostic(FeaturesResources.Illegal_whitespace_character, ch.Span); + } + } + + return null; + } + + private static EmbeddedDiagnostic? CheckObject(JsonObjectNode node, bool allowTrailingComma) + { + foreach (var child in node.Sequence) + { + if (child.Kind != JsonKind.Property) + return new EmbeddedDiagnostic(FeaturesResources.Only_properties_allowed_in_an_object, GetFirstToken(child).GetSpan()); + } + + if (!allowTrailingComma && node.Sequence.NodesAndTokens.Length != 0 && node.Sequence.NodesAndTokens.Length % 2 == 0) + return new EmbeddedDiagnostic(FeaturesResources.Trailing_comma_not_allowed, node.Sequence.NodesAndTokens[^1].Token.GetSpan()); + + return null; + } + + private static EmbeddedDiagnostic? CheckArray(JsonArrayNode node, bool allowTrailingComma) + => CheckProperSeparation(node.Sequence, allowTrailingComma); + + private static EmbeddedDiagnostic? CheckProperSeparation( + ImmutableArray sequence, + bool allowTrailingComma) + { + // Ensure that this sequence is actually a separated list. + for (int i = 0, n = sequence.Length; i < n; i++) + { + var child = sequence[i]; + if (i % 2 == 0) + { + if (child.Kind == JsonKind.CommaValue) + return new EmbeddedDiagnostic(string.Format(FeaturesResources._0_unexpected, ","), child.GetSpan()); + } + else + { + if (child.Kind != JsonKind.CommaValue) + return new EmbeddedDiagnostic(string.Format(FeaturesResources._0_expected, ","), GetFirstToken(child).GetSpan()); + } + } + + if (!allowTrailingComma && sequence.Length != 0 && sequence.Length % 2 == 0) + return new EmbeddedDiagnostic(FeaturesResources.Trailing_comma_not_allowed, sequence[^1].GetSpan()); + + return null; + } + + private static EmbeddedDiagnostic? CheckProperty(JsonPropertyNode node, bool allowComments) + { + if (node.NameToken.Kind != JsonKind.StringToken) + return new EmbeddedDiagnostic(FeaturesResources.Property_name_must_be_a_string, node.NameToken.GetSpan()); + + if (node.Value.Kind == JsonKind.CommaValue) + return new EmbeddedDiagnostic(FeaturesResources.Value_required, new TextSpan(node.ColonToken.VirtualChars[0].Span.End, 0)); + + return CheckString(node.NameToken, allowComments); + } + + private static EmbeddedDiagnostic? CheckLiteral(JsonLiteralNode node, bool allowComments) + => node.LiteralToken.Kind switch + { + // These are all json.net extensions. Disallow them all. + JsonKind.NaNLiteralToken or JsonKind.InfinityLiteralToken or JsonKind.UndefinedLiteralToken + => InvalidLiteral(node.LiteralToken), + JsonKind.NumberToken => CheckNumber(node.LiteralToken, allowComments), + JsonKind.StringToken => CheckString(node.LiteralToken, allowComments), + _ => null, + }; + + /* + From: https://tools.ietf.org/html/rfc8259 + + The representation of numbers is similar to that used in most + programming languages. A number is represented in base 10 using + decimal digits. It contains an integer component that may be + prefixed with an optional minus sign, which may be followed by a + fraction part and/or an exponent part. Leading zeros are not + allowed. + + A fraction part is a decimal point followed by one or more digits. + + An exponent part begins with the letter E in uppercase or lowercase, + which may be followed by a plus or minus sign. The E and optional + sign are followed by one or more digits. + + Numeric values that cannot be represented in the grammar below (such + as Infinity and NaN) are not permitted. + + number = [ minus ] int [ frac ] [ exp ] + decimal-point = %x2E ; . + digit1-9 = %x31-39 ; 1-9 + e = %x65 / %x45 ; e E + + exp = e [ minus / plus ] 1*DIGIT + frac = decimal-point 1*DIGIT + int = zero / ( digit1-9 *DIGIT ) + minus = %x2D ; - + plus = %x2B ; + + zero = %x30 ; 0 + */ + + private static readonly Regex s_validNumberRegex = + new( +@"^ +-? # [ minus ] +(0|([1-9][0-9]*)) # int +(\.[0-9]+)? # [ frac ] +([eE][-+]?[0-9]+)? # [ exp ] +$", + RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace); + + private static EmbeddedDiagnostic? CheckNumber(JsonToken literalToken, bool allowComments) + { + var literalText = literalToken.VirtualChars.CreateString(); + return !s_validNumberRegex.IsMatch(literalText) + ? new EmbeddedDiagnostic(FeaturesResources.Invalid_number, literalToken.GetSpan()) + : CheckToken(literalToken, allowComments); + } + + private static EmbeddedDiagnostic? CheckString(JsonToken literalToken, bool allowComments) + { + var chars = literalToken.VirtualChars; + if (chars[0] == '\'') + return new EmbeddedDiagnostic(FeaturesResources.Strings_must_start_with_double_quote_not_single_quote, chars[0].Span); + + for (int i = 1, n = chars.Length - 1; i < n; i++) + { + if (chars[i] < ' ') + return new EmbeddedDiagnostic(FeaturesResources.Illegal_string_character, chars[i].Span); + } + + // Lexer allows \' as that's ok in json.net. Check and block that here. + for (int i = 1, n = chars.Length - 1; i < n;) + { + if (chars[i] == '\\') + { + if (chars[i + 1] == '\'') + return new EmbeddedDiagnostic(FeaturesResources.Invalid_escape_sequence, TextSpan.FromBounds(chars[i].Span.Start, chars[i + 1].Span.End)); + + // Legal escape. just jump forward past it. Note, this works for simple + // escape and unicode \uXXXX escapes. + i += 2; + continue; + } + + i++; + } + + return CheckToken(literalToken, allowComments); + } + + private static EmbeddedDiagnostic? InvalidLiteral(JsonToken literalToken) + => new(string.Format(FeaturesResources._0_literal_not_allowed, literalToken.VirtualChars.CreateString()), literalToken.GetSpan()); + + private static EmbeddedDiagnostic? CheckNegativeLiteral(JsonNegativeLiteralNode node) + => new(string.Format(FeaturesResources._0_literal_not_allowed, "-Infinity"), node.GetSpan()); + + private static EmbeddedDiagnostic? CheckConstructor(JsonConstructorNode node) + => new(FeaturesResources.Constructors_not_allowed, node.NewKeyword.GetSpan()); + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonParser.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonParser.cs new file mode 100644 index 0000000000000..9f61c82948ba6 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonParser.cs @@ -0,0 +1,567 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + using static EmbeddedSyntaxHelpers; + using static JsonHelpers; + + using JsonNodeOrToken = EmbeddedSyntaxNodeOrToken; + using JsonToken = EmbeddedSyntaxToken; + using JsonTrivia = EmbeddedSyntaxTrivia; + using JsonSeparatedList = EmbeddedSeparatedSyntaxNodeList; + + /// + /// Parser used for reading in a sequence of s, and producing a out of it. Parsing will always succeed (except in the case of a + /// stack-overflow) and will consume the entire sequence of chars. General roslyn syntax + /// principles are held to (i.e. immutable, fully representative, etc.). + /// + /// The parser always parses out the same tree regardless of input. *However*, depending on the + /// flags passed to it, it may return a different set of *diagnostics*. Specifically, the + /// parser supports json.net parsing and strict RFC8259 (https://tools.ietf.org/html/rfc8259). + /// As such, the parser supports a superset of both, but then does a pass at the end to produce + /// appropriate diagnostics. + /// + /// + /// + /// Note: the json structure we parse out is actually very simple. It's effectively all lists + /// of values. We just treat almost everything as a 'value'. For + /// example, a (i.e. "x" = 0) is a 'value'. As such, it + /// can show up in arrays (i.e. ["x" = 0, "y" = 1]). This is not legal, but it greatly + /// simplifies parsing. Effectively, we just have recursive list parsing, where we accept any + /// sort of value in any sort of context. A later pass will then report errors for the wrong + /// sorts of values showing up in incorrect contexts. + /// + /// Note: We also treat commas (,) as being a 'value' on its own. This simplifies parsing + /// by allowing us to not have to represent Lists and SeparatedLists. It also helps model + /// things that are supported in json.net (like [1,,2]). Our post-parsing pass will + /// then ensure that these comma-values only show up in the right contexts. + /// + /// + [NonCopyable] + internal partial struct JsonParser + { + private static readonly string s_closeBracketExpected = string.Format(FeaturesResources._0_expected, ']'); + private static readonly string s_closeBraceExpected = string.Format(FeaturesResources._0_expected, '}'); + private static readonly string s_openParenExpected = string.Format(FeaturesResources._0_expected, '('); + private static readonly string s_closeParenExpected = string.Format(FeaturesResources._0_expected, ')'); + private static readonly string s_commaExpected = string.Format(FeaturesResources._0_expected, ','); + + private JsonLexer _lexer; + private JsonToken _currentToken; + private int _recursionDepth; + + // Fields used to keep track of what types of json values we're in. They're used for error + // recovery, specifically with respect to encountering unexpected tokens while parsing out a + // sequence of values. For example, if we have: ```{ a: [1, 2, }```, we will mark that + // we're both in an object and in an array. When we then encounter the errant ```}```, + // we'll see that we were in an object, and thus should stop parsing out the sequence for + // the array so that the ```}``` can be consume by the object we were in. However, if we + // just had ```[1, 2, }```, we would not be in an object, and we would just consume the + // ```}``` as a bogus value inside the array. + // + // This approach of keeping track of the parse contexts we're in, and using them to + // determine if we should consume or pop-out when encountering an error token, mirrors the + // same approach that we use in the C# and TS/JS parsers. + private bool _inObject; + private bool _inArray; + private bool _inConstructor; + + private JsonParser(VirtualCharSequence text) : this() + { + _lexer = new JsonLexer(text); + + // Get the first token. + ConsumeCurrentToken(); + } + + /// + /// Returns the latest token the lexer has produced, and then asks the lexer to + /// produce the next token after that. + /// + private JsonToken ConsumeCurrentToken() + { + var previous = _currentToken; + _currentToken = _lexer.ScanNextToken(); + return previous; + } + + /// + /// Given an input text, parses out a fully representative syntax tree and list of + /// diagnostics. Parsing should always succeed, except in the case of the stack + /// overflowing. + /// + public static JsonTree? TryParse(VirtualCharSequence text, JsonOptions options) + { + try + { + if (text.IsDefaultOrEmpty) + return null; + + return new JsonParser(text).ParseTree(options); + } + catch (InsufficientExecutionStackException) + { + return null; + } + } + + private JsonTree ParseTree(JsonOptions options) + { + var arraySequence = this.ParseSequence(); + Debug.Assert(_lexer.Position == _lexer.Text.Length); + Debug.Assert(_currentToken.Kind == JsonKind.EndOfFile); + + var root = new JsonCompilationUnit(arraySequence, _currentToken); + + // There are three forms of diagnostics we can detect. The first were generated directly when parsing and + // relate to unknown tokens encountered or tokens that were needed but not found. The second relates to a + // set of grammar check rules that apply to both strict and non-strict json. The last is the specific + // strict/loose checks we perform. We look for all three forms, but only report the first issue we found. + // We want to avoid reporting a ton of cascaded errors. + var diagnostic1 = GetFirstDiagnostic(root); + var diagnostic2 = CheckTopLevel(_lexer.Text, root); + var diagnostic3 = options.HasFlag(JsonOptions.Strict) + ? StrictSyntaxChecker.CheckRootSyntax(root, options) + : JsonNetSyntaxChecker.CheckSyntax(root); + + var diagnostic = Earliest(Earliest(diagnostic1, diagnostic2), diagnostic3); + + return new JsonTree(_lexer.Text, root, diagnostic == null + ? ImmutableArray.Empty + : ImmutableArray.Create(diagnostic.Value)); + } + + private static EmbeddedDiagnostic? Earliest(EmbeddedDiagnostic? d1, EmbeddedDiagnostic? d2) + { + if (d1 == null) + return d2; + + if (d2 == null) + return d1; + + return d1.Value.Span.Start <= d2.Value.Span.Start ? d1 : d2; + } + + /// + /// Checks for errors in json for both json.net and strict mode. + /// + private static EmbeddedDiagnostic? CheckTopLevel( + VirtualCharSequence text, JsonCompilationUnit compilationUnit) + { + var sequence = compilationUnit.Sequence; + if (sequence.IsEmpty) + { + // json is not allowed to be just whitespace. + // + // Note: we always have at least some content (either real nodes in the tree) or trivia on the EOF token + // as we only parse when we have a non-empty sequence of virtual chars to begin with. + if (text.Length > 0 && + compilationUnit.EndOfFileToken.LeadingTrivia.All( + t => t.Kind is JsonKind.WhitespaceTrivia or JsonKind.EndOfLineTrivia)) + { + return new EmbeddedDiagnostic(FeaturesResources.Syntax_error, GetSpan(text)); + } + + return null; + } + else if (sequence.Length >= 2) + { + // the top level can't have more than one actual value. + var firstToken = GetFirstToken(sequence[1]); + return new EmbeddedDiagnostic( + string.Format(FeaturesResources._0_unexpected, firstToken.VirtualChars[0]), + firstToken.GetSpan()); + } + else + { + var child = sequence.Single(); + + // Commas should never show up in the top level sequence. + if (child.Kind == JsonKind.CommaValue) + { + var emptyValue = (JsonCommaValueNode)child; + return new EmbeddedDiagnostic( + string.Format(FeaturesResources._0_unexpected, ','), + emptyValue.CommaToken.GetSpan()); + } + else if (child.Kind == JsonKind.Property) + { + var propertyValue = (JsonPropertyNode)child; + return new EmbeddedDiagnostic( + string.Format(FeaturesResources._0_unexpected, ':'), + propertyValue.ColonToken.GetSpan()); + } + + return CheckSyntax(child); + } + + static EmbeddedDiagnostic? CheckSyntax(JsonNode node) + { + var diagnostic = node.Kind switch + { + JsonKind.Array => CheckArray((JsonArrayNode)node), + _ => null, + }; + + return Earliest(diagnostic, CheckChildren(node)); + } + + static EmbeddedDiagnostic? CheckChildren(JsonNode node) + { + foreach (var child in node) + { + if (child.IsNode) + { + var diagnostic = CheckSyntax(child.Node); + if (diagnostic != null) + return diagnostic; + } + } + + return null; + } + + static EmbeddedDiagnostic? CheckArray(JsonArrayNode node) + { + foreach (var child in node.Sequence) + { + if (child.Kind == JsonKind.Property) + { + return new EmbeddedDiagnostic( + FeaturesResources.Properties_not_allowed_in_an_array, + ((JsonPropertyNode)child).ColonToken.GetSpan()); + } + } + + return CheckChildren(node); + } + } + + private static JsonToken GetFirstToken(JsonNodeOrToken nodeOrToken) + => nodeOrToken.IsNode ? GetFirstToken(nodeOrToken.Node.ChildAt(0)) : nodeOrToken.Token; + + private static EmbeddedDiagnostic? GetFirstDiagnostic(JsonNode node) + { + foreach (var child in node) + { + var diagnostic = GetFirstDiagnostic(child); + if (diagnostic != null) + return diagnostic; + } + + return null; + } + + private static EmbeddedDiagnostic? GetFirstDiagnostic(JsonNodeOrToken child) + => child.IsNode + ? GetFirstDiagnostic(child.Node) + : GetFirstDiagnostic(child.Token); + + private static EmbeddedDiagnostic? GetFirstDiagnostic(JsonToken token) + => GetFirstDiagnostic(token.LeadingTrivia) ?? token.Diagnostics.FirstOrNull() ?? GetFirstDiagnostic(token.TrailingTrivia); + + private static EmbeddedDiagnostic? GetFirstDiagnostic(ImmutableArray list) + { + foreach (var trivia in list) + { + var diagnostic = trivia.Diagnostics.FirstOrNull(); + if (diagnostic != null) + return diagnostic; + } + + return null; + } + + private ImmutableArray ParseSequence() + { + try + { + _recursionDepth++; + StackGuard.EnsureSufficientExecutionStack(_recursionDepth); + return ParseSequenceWorker(); + } + finally + { + _recursionDepth--; + } + } + + private ImmutableArray ParseSequenceWorker() + { + using var _ = ArrayBuilder.GetInstance(out var result); + + while (ShouldConsumeSequenceElement()) + result.Add(ParseValue()); + + return result.ToImmutable(); + } + + private JsonSeparatedList ParseCommaSeparatedSequence() + { + try + { + _recursionDepth++; + StackGuard.EnsureSufficientExecutionStack(_recursionDepth); + return ParseCommaSeparatedSequenceWorker(); + } + finally + { + _recursionDepth--; + } + } + + private JsonSeparatedList ParseCommaSeparatedSequenceWorker() + { + using var _ = ArrayBuilder.GetInstance(out var result); + var allProperties = true; + while (ShouldConsumeSequenceElement()) + { + var value = ParseValue(); + allProperties = allProperties && value.Kind == JsonKind.Property; + result.Add(value); + + // Try to consume a comma. If we don't see one, consume an empty one as a placeholder. Create a + // diagnostic message depending on if we've seen only properties before this point. If not, don't give + // a message about a missing comma. Instead, we'll give a specific message that we didn't get a + // property when we expected one. + if (ShouldConsumeSequenceElement()) + result.Add(ConsumeToken(JsonKind.CommaToken, allProperties ? s_commaExpected : null)); + } + + return new JsonSeparatedList(result.ToImmutable()); + } + + private bool ShouldConsumeSequenceElement() + => _currentToken.Kind switch + { + JsonKind.EndOfFile => false, + JsonKind.CloseBraceToken => !_inObject, + JsonKind.CloseBracketToken => !_inArray, + JsonKind.CloseParenToken => !_inConstructor, + _ => true + }; + + private JsonValueNode ParseValue() + => _currentToken.Kind switch + { + JsonKind.OpenBraceToken => ParseObject(), + JsonKind.OpenBracketToken => ParseArray(), + JsonKind.CommaToken => ParseCommaValue(), + _ => ParseLiteralOrPropertyOrConstructor(), + }; + + private static void SplitLiteral(JsonToken literalToken, out JsonToken minusToken, out JsonToken newLiteralToken) + { + minusToken = CreateToken( + JsonKind.MinusToken, literalToken.LeadingTrivia, + literalToken.VirtualChars.GetSubSequence(new TextSpan(0, 1)), + ImmutableArray.Empty); + newLiteralToken = CreateToken( + literalToken.Kind, + ImmutableArray.Empty, + literalToken.VirtualChars.GetSubSequence(TextSpan.FromBounds(1, literalToken.VirtualChars.Length)), + literalToken.TrailingTrivia, + literalToken.Diagnostics); + } + + private JsonPropertyNode ParseProperty(JsonToken stringLiteralOrText) + { + Debug.Assert(_currentToken.Kind == JsonKind.ColonToken); + + // Kind could be anything else we might have parsed as a value (for example, an integer/boolean literal). + if (stringLiteralOrText.Kind != JsonKind.StringToken) + stringLiteralOrText = stringLiteralOrText.With(kind: JsonKind.TextToken); + + var colonToken = ConsumeCurrentToken(); + + // Newtonsoft allows "{ a: , }" as a legal property. In that case, synthesize a missing value and allow the + // comma to be parsed as the next value in the sequence. The strict pass will error if it sees this missing + // comma-value as the value of a property. + if (_currentToken.Kind == JsonKind.CommaToken) + { + return new JsonPropertyNode( + stringLiteralOrText, colonToken, + new JsonCommaValueNode(CreateMissingToken(JsonKind.CommaToken))); + } + else if (_currentToken.Kind == JsonKind.EndOfFile) + { + return new JsonPropertyNode( + stringLiteralOrText, colonToken, + new JsonCommaValueNode(CreateMissingToken(JsonKind.CommaToken).AddDiagnosticIfNone(new EmbeddedDiagnostic( + FeaturesResources.Missing_property_value, + GetTokenStartPositionSpan(_currentToken))))); + } + + var value = ParseValue(); + if (value.Kind == JsonKind.Property) + { + // It's always illegal to have something like ```"a" : "b" : 1``` + var nestedProperty = (JsonPropertyNode)value; + value = new JsonPropertyNode( + nestedProperty.NameToken, + nestedProperty.ColonToken.AddDiagnosticIfNone(new EmbeddedDiagnostic( + FeaturesResources.Nested_properties_not_allowed, + nestedProperty.ColonToken.GetSpan())), + nestedProperty.Value); + } + + return new JsonPropertyNode(stringLiteralOrText, colonToken, value); + } + + private JsonValueNode ParseLiteralOrPropertyOrConstructor() + { + var textToken = ConsumeCurrentToken(); + return _currentToken.Kind == JsonKind.ColonToken + ? ParseProperty(textToken) + : ParseLiteralOrTextOrConstructor(textToken); + } + + private JsonValueNode ParseLiteralOrTextOrConstructor(JsonToken token) + { + if (token.Kind == JsonKind.StringToken) + return new JsonLiteralNode(token); + + // Look for constructors (a json.net extension). We'll report them as an error + // in strict model. + if (Matches(token, "new")) + return ParseConstructor(token); + + // Check for certain literal values. Some of these (like NaN) are json.net only. + // We'll check for these later in the strict-mode pass. + Debug.Assert(token.VirtualChars.Length > 0); + if (TryMatch(token, "NaN", JsonKind.NaNLiteralToken, out var newKind) || + TryMatch(token, "null", JsonKind.NullLiteralToken, out newKind) || + TryMatch(token, "true", JsonKind.TrueLiteralToken, out newKind) || + TryMatch(token, "false", JsonKind.FalseLiteralToken, out newKind) || + TryMatch(token, "Infinity", JsonKind.InfinityLiteralToken, out newKind) || + TryMatch(token, "undefined", JsonKind.UndefinedLiteralToken, out newKind)) + { + return new JsonLiteralNode(token.With(kind: newKind)); + } + + if (Matches(token, "-Infinity")) + { + SplitLiteral(token, out var minusToken, out var newLiteralToken); + + return new JsonNegativeLiteralNode( + minusToken, newLiteralToken.With(kind: JsonKind.InfinityLiteralToken)); + } + + var firstChar = token.VirtualChars[0]; + if (firstChar == '-' || firstChar == '.' || IsDigit(firstChar)) + return new JsonLiteralNode(token.With(kind: JsonKind.NumberToken)); + + return new JsonTextNode( + token.With(kind: JsonKind.TextToken).AddDiagnosticIfNone(new EmbeddedDiagnostic( + string.Format(FeaturesResources._0_unexpected, firstChar.ToString()), + firstChar.Span))); + } + + private JsonConstructorNode ParseConstructor(JsonToken token) + { + var savedInConstructor = _inConstructor; + _inConstructor = true; + + var result = new JsonConstructorNode( + token.With(kind: JsonKind.NewKeyword), + ConsumeToken(JsonKind.TextToken, FeaturesResources.Name_expected), + ConsumeToken(JsonKind.OpenParenToken, s_openParenExpected), + ParseSequence(), + ConsumeToken(JsonKind.CloseParenToken, s_closeParenExpected)); + + _inConstructor = savedInConstructor; + return result; + } + + private static bool TryMatch(JsonToken token, string val, JsonKind kind, out JsonKind newKind) + { + if (Matches(token, val)) + { + newKind = kind; + return true; + } + + newKind = default; + return false; + } + + private static bool Matches(JsonToken token, string val) + { + var chars = token.VirtualChars; + if (chars.Length != val.Length) + return false; + + for (var i = 0; i < val.Length; i++) + { + if (chars[i] != val[i]) + return false; + } + + return true; + } + + private static bool IsDigit(VirtualChar ch) + => ch.Value is >= '0' and <= '9'; + + private JsonCommaValueNode ParseCommaValue() + => new(ConsumeCurrentToken()); + + private JsonArrayNode ParseArray() + { + var savedInArray = _inArray; + _inArray = true; + + var result = new JsonArrayNode( + ConsumeCurrentToken(), + ParseSequence(), + ConsumeToken(JsonKind.CloseBracketToken, s_closeBracketExpected)); + + _inArray = savedInArray; + return result; + } + + private JsonObjectNode ParseObject() + { + var savedInObject = _inObject; + _inObject = true; + + var result = new JsonObjectNode( + ConsumeCurrentToken(), + ParseCommaSeparatedSequence(), + ConsumeToken(JsonKind.CloseBraceToken, s_closeBraceExpected)); + + _inObject = savedInObject; + return result; + } + + private JsonToken ConsumeToken(JsonKind kind, string? error) + { + if (_currentToken.Kind == kind) + return ConsumeCurrentToken(); + + var result = CreateMissingToken(kind); + if (error == null) + return result; + + return result.AddDiagnosticIfNone(new EmbeddedDiagnostic(error, GetTokenStartPositionSpan(_currentToken))); + } + + private TextSpan GetTokenStartPositionSpan(JsonToken token) + => token.Kind == JsonKind.EndOfFile + ? new TextSpan(_lexer.Text.Last().Span.End, 0) + : new TextSpan(token.VirtualChars[0].Span.Start, 0); + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonTree.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonTree.cs new file mode 100644 index 0000000000000..5ecebaa260fd0 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/JsonTree.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json +{ + internal sealed class JsonTree : EmbeddedSyntaxTree + { + public JsonTree( + VirtualCharSequence text, + JsonCompilationUnit root, + ImmutableArray diagnostics) : base(text, root, diagnostics) + { + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionAnalyzer.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionAnalyzer.cs new file mode 100644 index 0000000000000..3ce07d77c2f4e --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionAnalyzer.cs @@ -0,0 +1,105 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +{ + /// + /// Analyzer that helps find strings that are likely to be JSON and which we should offer the + /// enable language service features for. + /// + internal abstract class AbstractJsonDetectionAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer + { + public const string DiagnosticId = "JSON002"; + public const string StrictKey = nameof(StrictKey); + + private static readonly ImmutableDictionary s_strictProperties = + ImmutableDictionary.Empty.Add(StrictKey, ""); + + private readonly EmbeddedLanguageInfo _info; + + protected AbstractJsonDetectionAnalyzer(EmbeddedLanguageInfo info) + : base(DiagnosticId, + EnforceOnBuildValues.DetectProbableJsonStrings, + JsonFeatureOptions.DetectAndOfferEditorFeaturesForProbableJsonStrings, + new LocalizableResourceString(nameof(FeaturesResources.Probable_JSON_string_detected), FeaturesResources.ResourceManager, typeof(FeaturesResources)), + new LocalizableResourceString(nameof(FeaturesResources.Probable_JSON_string_detected), FeaturesResources.ResourceManager, typeof(FeaturesResources))) + { + _info = info; + } + + public override DiagnosticAnalyzerCategory GetAnalyzerCategory() + => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; + + public override bool OpenFileOnly(Options.OptionSet options) + => false; + + protected override void InitializeWorker(AnalysisContext context) + => context.RegisterSemanticModelAction(Analyze); + + public void Analyze(SemanticModelAnalysisContext context) + { + var semanticModel = context.SemanticModel; + var syntaxTree = semanticModel.SyntaxTree; + var cancellationToken = context.CancellationToken; + + var option = context.GetOption(JsonFeatureOptions.DetectAndOfferEditorFeaturesForProbableJsonStrings, syntaxTree.Options.Language); + if (!option) + return; + + var detector = JsonLanguageDetector.GetOrCreate(semanticModel.Compilation, _info); + var root = syntaxTree.GetRoot(cancellationToken); + Analyze(context, detector, root, cancellationToken); + } + + private void Analyze( + SemanticModelAnalysisContext context, + JsonLanguageDetector detector, + SyntaxNode node, + CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + foreach (var child in node.ChildNodesAndTokens()) + { + if (child.IsNode) + { + Analyze(context, detector, child.AsNode()!, cancellationToken); + } + else + { + var token = child.AsToken(); + + // If we have a string, and it's not being passed to a known JSON api (and it doesn't have a + // lang=json comment), but it is parseable as JSON with enough structure that we are confident it is + // json, then report that json features could light up here. + if (_info.IsAnyStringLiteral(token.RawKind) && + detector.TryParseString(token, context.SemanticModel, includeProbableStrings: false, cancellationToken) == null && + detector.IsProbablyJson(token, out _)) + { + var chars = _info.VirtualCharService.TryConvertToVirtualChars(token); + var strictTree = JsonParser.TryParse(chars, JsonOptions.Strict); + var properties = strictTree != null && strictTree.Diagnostics.Length == 0 + ? s_strictProperties + : ImmutableDictionary.Empty; + + // Show this as a hidden diagnostic so the user can enable json features explicitly if they + // want, but do not spam them with a ... notification if they don't want it. + context.ReportDiagnostic(DiagnosticHelper.Create( + this.Descriptor, + token.GetLocation(), + ReportDiagnostic.Hidden, + additionalLocations: null, + properties)); + } + } + } + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionCodeFixProvider.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionCodeFixProvider.cs new file mode 100644 index 0000000000000..ba58b37a4d19d --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionCodeFixProvider.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +{ + /// + /// Code fix impl for embedded json strings. + /// + internal abstract class AbstractJsonDetectionCodeFixProvider : SyntaxEditorBasedCodeFixProvider + { + private readonly EmbeddedLanguageInfo _info; + + protected AbstractJsonDetectionCodeFixProvider( + EmbeddedLanguageInfo info) + { + _info = info; + } + + protected abstract void AddComment(SyntaxEditor editor, SyntaxToken stringLiteral, string commentContents); + + internal override CodeFixCategory CodeFixCategory => CodeFixCategory.CodeStyle; + + public override ImmutableArray FixableDiagnosticIds + => ImmutableArray.Create(AbstractJsonDetectionAnalyzer.DiagnosticId); + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + context.RegisterCodeFix(new MyCodeAction( + c => FixAsync(context.Document, context.Diagnostics[0], c)), + context.Diagnostics); + + return Task.CompletedTask; + } + + public void Fix(SyntaxEditor editor, Diagnostic diagnostic, CancellationToken cancellationToken) + { + var stringLiteral = diagnostic.Location.FindToken(cancellationToken); + Debug.Assert(_info.IsAnyStringLiteral(stringLiteral.RawKind)); + + var commentContents = diagnostic.Properties.ContainsKey(AbstractJsonDetectionAnalyzer.StrictKey) + ? "lang=json,strict" + : "lang=json"; + + this.AddComment(editor, stringLiteral, commentContents); + } + + protected override Task FixAllAsync( + Document document, ImmutableArray diagnostics, + SyntaxEditor editor, CancellationToken cancellationToken) + { + foreach (var diagnostic in diagnostics) + Fix(editor, diagnostic, cancellationToken); + + return Task.CompletedTask; + } + + private class MyCodeAction : CodeAction.DocumentChangeAction + { + public MyCodeAction(Func> createChangedDocument) + : base(FeaturesResources.Enable_all_JSON_editor_features, createChangedDocument, nameof(FeaturesResources.Enable_all_JSON_editor_features)) + { + } + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDiagnosticAnalyzer.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDiagnosticAnalyzer.cs new file mode 100644 index 0000000000000..18f2545a74e41 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDiagnosticAnalyzer.cs @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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 Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +{ + /// + /// Analyzer that reports diagnostics in strings that we know are JSON text. + /// + internal abstract class AbstractJsonDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer + { + public const string DiagnosticId = "JSON001"; + + private readonly EmbeddedLanguageInfo _info; + + protected AbstractJsonDiagnosticAnalyzer(EmbeddedLanguageInfo info) + : base(DiagnosticId, + EnforceOnBuildValues.Json, + JsonFeatureOptions.ReportInvalidJsonPatterns, + new LocalizableResourceString(nameof(FeaturesResources.Invalid_JSON_pattern), FeaturesResources.ResourceManager, typeof(FeaturesResources)), + new LocalizableResourceString(nameof(FeaturesResources.JSON_issue_0), FeaturesResources.ResourceManager, typeof(FeaturesResources))) + { + _info = info; + } + + public override DiagnosticAnalyzerCategory GetAnalyzerCategory() + => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; + + public override bool OpenFileOnly(Options.OptionSet options) + => false; + + protected override void InitializeWorker(AnalysisContext context) + => context.RegisterSemanticModelAction(Analyze); + + public void Analyze(SemanticModelAnalysisContext context) + { + var semanticModel = context.SemanticModel; + var syntaxTree = semanticModel.SyntaxTree; + var cancellationToken = context.CancellationToken; + + var option = context.GetOption(JsonFeatureOptions.ReportInvalidJsonPatterns, syntaxTree.Options.Language); + if (!option) + return; + + var detector = JsonLanguageDetector.GetOrCreate(semanticModel.Compilation, _info); + var root = syntaxTree.GetRoot(cancellationToken); + Analyze(context, detector, root, cancellationToken); + } + + private void Analyze( + SemanticModelAnalysisContext context, + JsonLanguageDetector detector, + SyntaxNode node, + CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + foreach (var child in node.ChildNodesAndTokens()) + { + if (child.IsNode) + { + Analyze(context, detector, child.AsNode()!, cancellationToken); + } + else + { + var token = child.AsToken(); + if (_info.IsAnyStringLiteral(token.RawKind)) + { + var tree = detector.TryParseString(token, context.SemanticModel, includeProbableStrings: false, cancellationToken); + if (tree != null) + { + foreach (var diag in tree.Diagnostics) + { + context.ReportDiagnostic(DiagnosticHelper.Create( + this.Descriptor, + Location.Create(context.SemanticModel.SyntaxTree, diag.Span), + ReportDiagnostic.Warn, + additionalLocations: null, + properties: null, + diag.Message)); + } + } + } + } + } + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedClassifier.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedClassifier.cs new file mode 100644 index 0000000000000..ea29440eedc04 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedClassifier.cs @@ -0,0 +1,194 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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 Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +{ + using System.Collections.Immutable; + using Microsoft.CodeAnalysis.Classification.Classifiers; + using static EmbeddedSyntaxHelpers; + + using JsonToken = EmbeddedSyntaxToken; + using JsonTrivia = EmbeddedSyntaxTrivia; + + /// + /// Classifier impl for embedded json strings. + /// + internal class JsonEmbeddedClassifier : AbstractSyntaxClassifier + { + private static readonly ObjectPool s_visitorPool = new(() => new Visitor()); + private readonly EmbeddedLanguageInfo _info; + + public override ImmutableArray SyntaxTokenKinds { get; } + + public JsonEmbeddedClassifier(EmbeddedLanguageInfo info) + { + _info = info; + SyntaxTokenKinds = info.AllStringLiteralKinds; + } + + public override void AddClassifications( + SyntaxToken token, + SemanticModel semanticModel, + ClassificationOptions options, + ArrayBuilder result, + CancellationToken cancellationToken) + { + if (!_info.IsAnyStringLiteral(token.RawKind)) + return; + + if (!options.ColorizeJsonPatterns) + return; + + var detector = JsonLanguageDetector.GetOrCreate(semanticModel.Compilation, _info); + + // We do support json classification in strings that look very likely to be json, even if we aren't 100% + // certain if it truly is json. + var tree = detector.TryParseString(token, semanticModel, includeProbableStrings: true, cancellationToken); + if (tree == null) + return; + + var visitor = s_visitorPool.Allocate(); + try + { + visitor.Result = result; + AddClassifications(tree.Root, visitor, result); + } + finally + { + visitor.Result = null; + s_visitorPool.Free(visitor); + } + } + + private static void AddClassifications(JsonNode node, Visitor visitor, ArrayBuilder result) + { + node.Accept(visitor); + + foreach (var child in node) + { + if (child.IsNode) + { + AddClassifications(child.Node, visitor, result); + } + else + { + AddTriviaClassifications(child.Token, result); + } + } + } + + private static void AddTriviaClassifications(JsonToken token, ArrayBuilder result) + { + foreach (var trivia in token.LeadingTrivia) + AddTriviaClassifications(trivia, result); + + foreach (var trivia in token.TrailingTrivia) + AddTriviaClassifications(trivia, result); + } + + private static void AddTriviaClassifications(JsonTrivia trivia, ArrayBuilder result) + { + if (trivia.Kind is JsonKind.MultiLineCommentTrivia or JsonKind.SingleLineCommentTrivia && + trivia.VirtualChars.Length > 0) + { + result.Add(new ClassifiedSpan( + ClassificationTypeNames.JsonComment, GetSpan(trivia.VirtualChars))); + } + } + + private class Visitor : IJsonNodeVisitor + { + public ArrayBuilder? Result; + + private void AddClassification(JsonToken token, string typeName) + { + if (!token.IsMissing) + Result!.Add(new ClassifiedSpan(typeName, token.GetSpan())); + } + + public void Visit(JsonCompilationUnit node) + { + // nothing to do. + } + + public void Visit(JsonArrayNode node) + { + AddClassification(node.OpenBracketToken, ClassificationTypeNames.JsonArray); + AddClassification(node.CloseBracketToken, ClassificationTypeNames.JsonArray); + } + + public void Visit(JsonObjectNode node) + { + AddClassification(node.OpenBraceToken, ClassificationTypeNames.JsonObject); + AddClassification(node.CloseBraceToken, ClassificationTypeNames.JsonObject); + } + + public void Visit(JsonPropertyNode node) + { + AddClassification(node.NameToken, ClassificationTypeNames.JsonPropertyName); + AddClassification(node.ColonToken, ClassificationTypeNames.JsonPunctuation); + } + + public void Visit(JsonConstructorNode node) + { + AddClassification(node.NewKeyword, ClassificationTypeNames.JsonKeyword); + AddClassification(node.NameToken, ClassificationTypeNames.JsonConstructorName); + AddClassification(node.OpenParenToken, ClassificationTypeNames.JsonPunctuation); + AddClassification(node.CloseParenToken, ClassificationTypeNames.JsonPunctuation); + } + + public void Visit(JsonLiteralNode node) + => VisitLiteral(node.LiteralToken); + + private void VisitLiteral(JsonToken literalToken) + { + switch (literalToken.Kind) + { + case JsonKind.NumberToken: + AddClassification(literalToken, ClassificationTypeNames.JsonNumber); + return; + + case JsonKind.StringToken: + AddClassification(literalToken, ClassificationTypeNames.JsonString); + return; + + case JsonKind.TrueLiteralToken: + case JsonKind.FalseLiteralToken: + case JsonKind.NullLiteralToken: + case JsonKind.UndefinedLiteralToken: + case JsonKind.NaNLiteralToken: + case JsonKind.InfinityLiteralToken: + AddClassification(literalToken, ClassificationTypeNames.JsonKeyword); + return; + + default: + AddClassification(literalToken, ClassificationTypeNames.JsonText); + return; + } + } + + public void Visit(JsonNegativeLiteralNode node) + { + AddClassification(node.MinusToken, ClassificationTypeNames.JsonOperator); + VisitLiteral(node.LiteralToken); + } + + public void Visit(JsonTextNode node) + { + VisitLiteral(node.TextToken); + } + + public void Visit(JsonCommaValueNode node) + { + AddClassification(node.CommaToken, ClassificationTypeNames.JsonPunctuation); + } + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedLanguage.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedLanguage.cs new file mode 100644 index 0000000000000..8514e1b965138 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedLanguage.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Classification.Classifiers; +using Microsoft.CodeAnalysis.Completion.Providers; +using Microsoft.CodeAnalysis.DocumentHighlighting; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +{ + internal class JsonEmbeddedLanguage : IEmbeddedLanguageFeatures + { + public ISyntaxClassifier Classifier { get; } + + // No document-highlights for embedded json currently. + public IDocumentHighlightsService? DocumentHighlightsService => null; + + // No completion for embedded json currently. + public EmbeddedLanguageCompletionProvider? CompletionProvider => null; + + public JsonEmbeddedLanguage(EmbeddedLanguageInfo info) + { + Classifier = new JsonEmbeddedClassifier(info); + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonFeatureOptions.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonFeatureOptions.cs new file mode 100644 index 0000000000000..076a94d7ea45b --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonFeatureOptions.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.Immutable; +using System.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Options.Providers; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; + +internal class JsonFeatureOptions +{ + public static PerLanguageOption2 ReportInvalidJsonPatterns = + new(nameof(JsonFeatureOptions), + nameof(ReportInvalidJsonPatterns), + defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.ReportInvalidJsonPatterns")); + + public static PerLanguageOption2 HighlightRelatedJsonComponentsUnderCursor = + new(nameof(JsonFeatureOptions), + nameof(HighlightRelatedJsonComponentsUnderCursor), + defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.HighlightRelatedJsonComponentsUnderCursor")); + + public static PerLanguageOption2 DetectAndOfferEditorFeaturesForProbableJsonStrings = + new(nameof(JsonFeatureOptions), + nameof(DetectAndOfferEditorFeaturesForProbableJsonStrings), + defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.DetectAndOfferEditorFeaturesForProbableJsonStrings")); +} + +[ExportSolutionOptionProvider, Shared] +internal class JsonOptionsProvider : IOptionProvider +{ + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public JsonOptionsProvider() + { + } + + public ImmutableArray Options { get; } = ImmutableArray.Create( + JsonFeatureOptions.ReportInvalidJsonPatterns, + JsonFeatureOptions.HighlightRelatedJsonComponentsUnderCursor, + JsonFeatureOptions.DetectAndOfferEditorFeaturesForProbableJsonStrings); +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetector.cs new file mode 100644 index 0000000000000..10cbe7ed5a866 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetector.cs @@ -0,0 +1,229 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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 System.Linq; +using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +{ + /// + /// Helper class to detect json in string tokens in a document efficiently. + /// + internal class JsonLanguageDetector : AbstractLanguageDetector + { + private const string JsonParameterName = "json"; + private const string ParseMethodName = "Parse"; + + private static readonly HashSet s_typeNamesOfInterest = new() + { + "Newtonsoft.Json.Linq.JToken", + "Newtonsoft.Json.Linq.JObject", + "Newtonsoft.Json.Linq.JArray", + "System.Text.Json.JsonDocument", + }; + + private static readonly ConditionalWeakTable s_compilationToDetector = new(); + + private readonly ISet _typesOfInterest; + + /// + /// Helps match patterns of the form: language=json + /// + /// All matching is case insensitive, with spaces allowed between the punctuation. + /// + private static readonly LanguageCommentDetector s_languageCommentDetector = new("json"); + + public JsonLanguageDetector( + EmbeddedLanguageInfo info, + ISet typesOfInterest) + : base("Json", info, s_languageCommentDetector) + { + _typesOfInterest = typesOfInterest; + } + + public static JsonLanguageDetector GetOrCreate( + Compilation compilation, EmbeddedLanguageInfo info) + { + // Do a quick non-allocating check first. + if (s_compilationToDetector.TryGetValue(compilation, out var detector)) + return detector; + + return s_compilationToDetector.GetValue(compilation, _ => Create(compilation, info)); + } + + private static JsonLanguageDetector Create( + Compilation compilation, EmbeddedLanguageInfo info) + { + var types = s_typeNamesOfInterest.Select(t => compilation.GetTypeByMetadataName(t)).WhereNotNull().ToSet(); + return new JsonLanguageDetector(info, types); + } + + /// + /// [StringSyntax(Json)] means we're targetting .net, which means we're strict by default if we don't see any + /// options. + /// + protected override JsonOptions GetStringSyntaxDefaultOptions() + => JsonOptions.Strict; + + protected override JsonTree? TryParse(VirtualCharSequence chars, JsonOptions options) + => JsonParser.TryParse(chars, options); + + /// + /// + /// If is true, then this will also succeed on a string-literal like + /// that strongly appears to have JSON in it. This allows some features to light up + /// automatically on code that is strongly believed to be JSON, but which is not passed to a known JSON api, + /// and does not have a comment on it stating it is JSON. + /// + public JsonTree? TryParseString(SyntaxToken token, SemanticModel semanticModel, bool includeProbableStrings, CancellationToken cancellationToken) + { + var result = TryParseString(token, semanticModel, cancellationToken); + if (result != null) + return result; + + if (includeProbableStrings && IsProbablyJson(token, out var tree)) + return tree; + + return null; + } + + /// + /// Returns if this string-like is likely a JSON literal. As + /// many simple strings are legal JSON (like 0) we require enough structure here to feel confident that + /// this truly is JSON. Currently, this means it must have at least one { ... } object literal, and that + /// literal must have at least one "prop": val property in it. + /// + public bool IsProbablyJson(SyntaxToken token, [NotNullWhen(true)] out JsonTree? tree) + { + var chars = this.Info.VirtualCharService.TryConvertToVirtualChars(token); + tree = JsonParser.TryParse(chars, JsonOptions.Loose); + if (tree == null || !tree.Diagnostics.IsEmpty) + return false; + + return ContainsProbableJsonObject(tree.Root); + } + + private static bool ContainsProbableJsonObject(JsonNode node) + { + if (node.Kind == JsonKind.Object) + { + var objNode = (JsonObjectNode)node; + if (objNode.Sequence.Length >= 1) + return true; + } + + foreach (var child in node) + { + if (child.IsNode) + { + if (ContainsProbableJsonObject(child.Node)) + return true; + } + } + + return false; + } + + protected override bool IsArgumentToWellKnownAPI( + SyntaxToken token, + SyntaxNode argumentNode, + SemanticModel semanticModel, + CancellationToken cancellationToken, + out JsonOptions options) + { + var syntaxFacts = Info.SyntaxFacts; + var argumentList = argumentNode.GetRequiredParent(); + var invocationOrCreation = argumentList.Parent; + if (syntaxFacts.IsInvocationExpression(invocationOrCreation)) + { + var invokedExpression = syntaxFacts.GetExpressionOfInvocationExpression(invocationOrCreation); + var name = GetNameOfInvokedExpression(invokedExpression); + if (syntaxFacts.StringComparer.Equals(name, ParseMethodName)) + { + // Is a string argument to a method that looks like it could be a json-parsing + // method. Need to do deeper analysis + var symbol = semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken).GetAnySymbol(); + if (symbol is IMethodSymbol { DeclaredAccessibility: Accessibility.Public, IsStatic: true } && + _typesOfInterest.Contains(symbol.ContainingType) && + IsArgumentToSuitableParameter(semanticModel, argumentNode, cancellationToken)) + { + options = symbol.ContainingType.Name == nameof(JsonDocument) ? JsonOptions.Strict : default; + options |= GetOptionsFromSiblingArgument(argumentNode, semanticModel, cancellationToken) ?? default; + return true; + } + } + } + + options = default; + return false; + } + + protected override bool TryGetOptions( + SemanticModel semanticModel, ITypeSymbol exprType, SyntaxNode expr, CancellationToken cancellationToken, out JsonOptions options) + { + options = default; + + // look for an argument of the form `new JsonDocumentOptions { AllowTrailingCommas = ..., CommentHandling = ... }` + + if (exprType.Name != nameof(JsonDocumentOptions)) + return false; + + // once we see a JsonDocumentOptions, we know this is the .net parser and we should be strict. + options = JsonOptions.Strict; + var syntaxFacts = Info.SyntaxFacts; + expr = syntaxFacts.WalkDownParentheses(expr); + if (syntaxFacts.IsObjectCreationExpression(expr) || + syntaxFacts.IsImplicitObjectCreationExpression(expr)) + { + syntaxFacts.GetPartsOfBaseObjectCreationExpression(expr, out var argumentList, out var objectInitializer); + if (syntaxFacts.IsObjectMemberInitializer(objectInitializer)) + { + var initializers = syntaxFacts.GetInitializersOfObjectMemberInitializer(objectInitializer); + foreach (var initializer in initializers) + { + if (syntaxFacts.IsNamedMemberInitializer(initializer)) + { + syntaxFacts.GetPartsOfNamedMemberInitializer(initializer, out var name, out var initExpr); + var propName = syntaxFacts.GetIdentifierOfIdentifierName(name).ValueText; + if (syntaxFacts.StringComparer.Equals(propName, nameof(JsonDocumentOptions.AllowTrailingCommas)) && + semanticModel.GetConstantValue(initExpr).Value is true) + { + options |= JsonOptions.TrailingCommas; + } + else if (syntaxFacts.StringComparer.Equals(propName, nameof(JsonDocumentOptions.CommentHandling)) && + semanticModel.GetConstantValue(initExpr).Value is (byte)JsonCommentHandling.Allow or (byte)JsonCommentHandling.Skip) + { + options |= JsonOptions.Comments; + } + } + } + } + } + + return true; + } + + private bool IsArgumentToSuitableParameter( + SemanticModel semanticModel, SyntaxNode argumentNode, CancellationToken cancellationToken) + { + var parameter = Info.SemanticFacts.FindParameterForArgument(semanticModel, argumentNode, cancellationToken); + return parameter?.Name == JsonParameterName; + } + + internal static class TestAccessor + { + public static bool TryMatch(string text, out JsonOptions options) + => s_languageCommentDetector.TryMatch(text, out options); + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/AbstractRegexDiagnosticAnalyzer.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/AbstractRegexDiagnosticAnalyzer.cs similarity index 77% rename from src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/AbstractRegexDiagnosticAnalyzer.cs rename to src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/AbstractRegexDiagnosticAnalyzer.cs index aaef642242d26..9dc30d83f5350 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/AbstractRegexDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/AbstractRegexDiagnosticAnalyzer.cs @@ -9,10 +9,8 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; -using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; -using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions.LanguageServices; -namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices { /// /// Analyzer that reports diagnostics in strings that we know are regex text. @@ -26,8 +24,8 @@ internal abstract class AbstractRegexDiagnosticAnalyzer : AbstractBuiltInCodeSty protected AbstractRegexDiagnosticAnalyzer(EmbeddedLanguageInfo info) : base(DiagnosticId, EnforceOnBuildValues.Regex, - RegularExpressionsOptions.ReportInvalidRegexPatterns, - new LocalizableResourceString(nameof(FeaturesResources.Regex_issue_0), FeaturesResources.ResourceManager, typeof(FeaturesResources)), + option: null, + new LocalizableResourceString(nameof(FeaturesResources.Invalid_regex_pattern), FeaturesResources.ResourceManager, typeof(FeaturesResources)), new LocalizableResourceString(nameof(FeaturesResources.Regex_issue_0), FeaturesResources.ResourceManager, typeof(FeaturesResources))) { _info = info; @@ -45,17 +43,11 @@ public void Analyze(SemanticModelAnalysisContext context) var syntaxTree = semanticModel.SyntaxTree; var cancellationToken = context.CancellationToken; - var option = context.GetOption(RegularExpressionsOptions.ReportInvalidRegexPatterns, syntaxTree.Options.Language); + var option = context.GetIdeOptions().ReportInvalidRegexPatterns; if (!option) - { return; - } - var detector = RegexPatternDetector.TryGetOrCreate(semanticModel.Compilation, _info); - if (detector == null) - { - return; - } + var detector = RegexLanguageDetector.GetOrCreate(semanticModel.Compilation, _info); // Use an actual stack object so that we don't blow the actual stack through recursion. var root = syntaxTree.GetRoot(cancellationToken); @@ -82,12 +74,14 @@ public void Analyze(SemanticModelAnalysisContext context) } private void AnalyzeToken( - SemanticModelAnalysisContext context, RegexPatternDetector detector, - SyntaxToken token, CancellationToken cancellationToken) + SemanticModelAnalysisContext context, + RegexLanguageDetector detector, + SyntaxToken token, + CancellationToken cancellationToken) { - if (token.RawKind == _info.StringLiteralTokenKind) + if (_info.IsAnyStringLiteral(token.RawKind)) { - var tree = detector.TryParseRegexPattern(token, context.SemanticModel, cancellationToken); + var tree = detector.TryParseString(token, context.SemanticModel, cancellationToken); if (tree != null) { foreach (var diag in tree.Diagnostics) diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/EmbeddedCompletionContext.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs similarity index 98% rename from src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/EmbeddedCompletionContext.cs rename to src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs index d0924e797b1c9..36c8508cba6b9 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/EmbeddedCompletionContext.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices { internal partial class RegexEmbeddedCompletionProvider { diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexDocumentHighlightsService.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexDocumentHighlightsService.cs similarity index 97% rename from src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexDocumentHighlightsService.cs rename to src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexDocumentHighlightsService.cs index 3f0406da5edeb..a7c1228ac5242 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexDocumentHighlightsService.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices { using RegexToken = EmbeddedSyntaxToken; @@ -60,11 +60,9 @@ private ImmutableArray GetHighlights(RegexTree tree, int position private ImmutableArray GetReferences(RegexTree tree, int position) { - var virtualChar = tree.Text.FirstOrNull(vc => vc.Span.Contains(position)); + var virtualChar = tree.Text.Find(position); if (virtualChar == null) - { return ImmutableArray.Empty; - } var ch = virtualChar.Value; return FindReferenceHighlights(tree, ch); diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexEmbeddedCompletionProvider.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedCompletionProvider.cs similarity index 99% rename from src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexEmbeddedCompletionProvider.cs rename to src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedCompletionProvider.cs index 1210235589384..224313bd6b7a1 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexEmbeddedCompletionProvider.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedCompletionProvider.cs @@ -17,7 +17,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices { using static FeaturesResources; using RegexToken = EmbeddedSyntaxToken; @@ -149,7 +149,7 @@ private void ProvideCompletions(EmbeddedCompletionContext context) // We added no items, but the user explicitly asked for completion. Add all the // items we can to help them out. - var virtualChar = context.Tree.Text.FirstOrNull(vc => vc.Span.Contains(context.Position)); + var virtualChar = context.Tree.Text.Find(context.Position); var inCharacterClass = virtualChar != null && IsInCharacterClass(context.Tree.Root, virtualChar.Value); ProvideBackslashCompletions(context, inCharacterClass, parentOpt: null); @@ -164,7 +164,7 @@ private void ProvideCompletions(EmbeddedCompletionContext context) /// private void ProvideCompletionsBasedOffOfPrecedingCharacter(EmbeddedCompletionContext context) { - var previousVirtualCharOpt = context.Tree.Text.FirstOrNull(vc => vc.Span.Contains(context.Position - 1)); + var previousVirtualCharOpt = context.Tree.Text.Find(context.Position - 1); if (previousVirtualCharOpt == null) { // We didn't have a previous character. Can't determine the set of diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexEmbeddedLanguage.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedLanguage.cs similarity index 82% rename from src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexEmbeddedLanguage.cs rename to src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedLanguage.cs index 4af305ff6468b..921a70d8c55b1 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexEmbeddedLanguage.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedLanguage.cs @@ -5,16 +5,14 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification.Classifiers; -using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.DocumentHighlighting; using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; -using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions.LanguageServices; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; -namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices { internal class RegexEmbeddedLanguage : IEmbeddedLanguageFeatures { @@ -45,13 +43,10 @@ public RegexEmbeddedLanguage( { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); - var syntaxFacts = document.GetLanguageService(); - if (!RegexPatternDetector.IsPossiblyPatternToken(token, syntaxFacts)) - return default; var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var detector = RegexPatternDetector.TryGetOrCreate(semanticModel.Compilation, this.Info); - var tree = detector?.TryParseRegexPattern(token, semanticModel, cancellationToken); + var detector = RegexLanguageDetector.GetOrCreate(semanticModel.Compilation, this.Info); + var tree = detector.TryParseString(token, semanticModel, cancellationToken); return tree == null ? default : (tree, token); } diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexItem.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexItem.cs similarity index 96% rename from src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexItem.cs rename to src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexItem.cs index 3b5d3e5a4e70b..1bdd480918464 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexItem.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexItem.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Microsoft.CodeAnalysis.Completion; -namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices { internal partial class RegexEmbeddedCompletionProvider { diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexLanguageDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexLanguageDetector.cs new file mode 100644 index 0000000000000..d5023329b1e10 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexLanguageDetector.cs @@ -0,0 +1,230 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text.RegularExpressions; +using System.Threading; +using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; +using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.Features.RQName.Nodes; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices +{ + + /// + /// Helper class to detect regex pattern tokens in a document efficiently. + /// + internal sealed class RegexLanguageDetector : AbstractLanguageDetector + { + private const string _patternName = "pattern"; + + /// + /// Cache so that we can reuse the same when analyzing a particular + /// compilation model. This saves the time from having to recreate this for every string literal that features + /// examine for a particular compilation. + /// + private static readonly ConditionalWeakTable _modelToDetector = new(); + + private readonly INamedTypeSymbol? _regexType; + private readonly HashSet _methodNamesOfInterest; + + private static readonly LanguageCommentDetector s_languageCommentDetector = new("regex", "regexp"); + + public RegexLanguageDetector( + EmbeddedLanguageInfo info, + INamedTypeSymbol? regexType, + HashSet methodNamesOfInterest) + : base("Regex", info, s_languageCommentDetector) + { + _regexType = regexType; + _methodNamesOfInterest = methodNamesOfInterest; + } + + public static RegexLanguageDetector GetOrCreate( + Compilation compilation, EmbeddedLanguageInfo info) + { + // Do a quick non-allocating check first. + if (_modelToDetector.TryGetValue(compilation, out var detector)) + return detector; + + return _modelToDetector.GetValue(compilation, _ => Create(compilation, info)); + } + + private static RegexLanguageDetector Create( + Compilation compilation, EmbeddedLanguageInfo info) + { + var regexType = compilation.GetTypeByMetadataName(typeof(Regex).FullName!); + var methodNamesOfInterest = GetMethodNamesOfInterest(regexType, info.SyntaxFacts); + return new RegexLanguageDetector(info, regexType, methodNamesOfInterest); + } + + /// + /// Finds public, static methods in that have a parameter called + /// 'pattern'. These are helpers (like + /// where at least one (but not necessarily more) of the parameters should be treated as a + /// pattern. + /// + private static HashSet GetMethodNamesOfInterest(INamedTypeSymbol? regexType, ISyntaxFacts syntaxFacts) + { + var result = syntaxFacts.IsCaseSensitive + ? new HashSet() + : new HashSet(StringComparer.OrdinalIgnoreCase); + + if (regexType != null) + { + result.AddRange( + from method in regexType.GetMembers().OfType() + where method.DeclaredAccessibility == Accessibility.Public + where method.IsStatic + where method.Parameters.Any(p => p.Name == _patternName) + select method.Name); + } + + return result; + } + + protected override bool IsArgumentToWellKnownAPI( + SyntaxToken token, + SyntaxNode argumentNode, + SemanticModel semanticModel, + CancellationToken cancellationToken, + out RegexOptions options) + { + if (_regexType == null) + { + options = default; + return false; + } + + var syntaxFacts = Info.SyntaxFacts; + var argumentList = argumentNode.GetRequiredParent(); + var invocationOrCreation = argumentList.Parent; + if (syntaxFacts.IsInvocationExpression(invocationOrCreation)) + { + var invokedExpression = syntaxFacts.GetExpressionOfInvocationExpression(invocationOrCreation); + var name = GetNameOfInvokedExpression(invokedExpression); + if (name != null && _methodNamesOfInterest.Contains(name)) + { + // Is a string argument to a method that looks like it could be a Regex method. + // Need to do deeper analysis. + + // Note we do not use GetAllSymbols here because we don't want to incur the + // allocation. + var symbolInfo = semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken); + var method = symbolInfo.Symbol; + if (TryAnalyzeInvocation(_regexType, argumentNode, semanticModel, method, cancellationToken, out options)) + return true; + + foreach (var candidate in symbolInfo.CandidateSymbols) + { + if (TryAnalyzeInvocation(_regexType, argumentNode, semanticModel, candidate, cancellationToken, out options)) + return true; + } + } + } + else if (syntaxFacts.IsObjectCreationExpression(invocationOrCreation)) + { + var typeNode = syntaxFacts.GetTypeOfObjectCreationExpression(invocationOrCreation); + var name = GetNameOfType(typeNode, syntaxFacts); + if (name != null) + { + if (syntaxFacts.StringComparer.Compare(nameof(Regex), name) == 0) + { + var constructor = semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken).GetAnySymbol(); + if (_regexType.Equals(constructor?.ContainingType)) + { + // Argument to "new Regex". Need to do deeper analysis + return AnalyzeStringLiteral(argumentNode, semanticModel, cancellationToken, out options); + } + } + } + } + else if (syntaxFacts.IsImplicitObjectCreationExpression(invocationOrCreation)) + { + var constructor = semanticModel.GetSymbolInfo(invocationOrCreation, cancellationToken).GetAnySymbol(); + if (_regexType.Equals(constructor?.ContainingType)) + { + // Argument to "new Regex". Need to do deeper analysis + return AnalyzeStringLiteral(argumentNode, semanticModel, cancellationToken, out options); + } + } + + options = default; + return false; + } + + private bool TryAnalyzeInvocation( + INamedTypeSymbol regexType, + SyntaxNode argumentNode, + SemanticModel semanticModel, + ISymbol? method, + CancellationToken cancellationToken, + out RegexOptions options) + { + if (method != null && + method.DeclaredAccessibility == Accessibility.Public && + method.IsStatic && + regexType.Equals(method.ContainingType)) + { + return AnalyzeStringLiteral(argumentNode, semanticModel, cancellationToken, out options); + } + + options = default; + return false; + } + + protected override RegexTree? TryParse(VirtualCharSequence chars, RegexOptions options) + => RegexParser.TryParse(chars, options); + + private bool AnalyzeStringLiteral( + SyntaxNode argumentNode, + SemanticModel semanticModel, + CancellationToken cancellationToken, + out RegexOptions options) + { + options = default; + + var parameter = Info.SemanticFacts.FindParameterForArgument(semanticModel, argumentNode, cancellationToken); + if (parameter?.Name != _patternName) + { + return false; + } + + options = GetOptionsFromSiblingArgument(argumentNode, semanticModel, cancellationToken) ?? default; + return true; + } + + protected override bool TryGetOptions( + SemanticModel semanticModel, ITypeSymbol exprType, SyntaxNode expr, CancellationToken cancellationToken, out RegexOptions options) + { + if (exprType.Name == nameof(RegexOptions)) + { + var constVal = semanticModel.GetConstantValue(expr, cancellationToken); + if (constVal.Value is int intValue) + { + options = (RegexOptions)intValue; + return true; + } + } + + options = default; + return false; + } + + internal static class TestAccessor + { + public static bool TryMatch(string text, out RegexOptions options) + => s_languageCommentDetector.TryMatch(text, out options); + } + } +} diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexPatternDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexPatternDetector.cs deleted file mode 100644 index 7604a51411574..0000000000000 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexPatternDetector.cs +++ /dev/null @@ -1,404 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text.RegularExpressions; -using System.Threading; -using Microsoft.CodeAnalysis.EmbeddedLanguages.LanguageServices; -using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions.LanguageServices -{ - /// - /// Helper class to detect regex pattern tokens in a document efficiently. - /// - internal sealed class RegexPatternDetector - { - private const string _patternName = "pattern"; - - /// - /// Cache so that we can reuse the same when analyzing a particular - /// compilation model. This saves the time from having to recreate this for every string literal that features - /// examine for a particular compilation. - /// - private static readonly ConditionalWeakTable _modelToDetector = new(); - - private readonly EmbeddedLanguageInfo _info; - private readonly INamedTypeSymbol _regexType; - private readonly HashSet _methodNamesOfInterest; - - /// - /// Helps match patterns of the form: language=regex,option1,option2,option3 - /// - /// All matching is case insensitive, with spaces allowed between the punctuation. - /// 'regex' or 'regexp' are both allowed. Option values will be or'ed together - /// to produce final options value. If an unknown option is encountered, processing - /// will stop with whatever value has accumulated so far. - /// - /// Option names are the values from the enum. - /// - private static readonly Regex s_languageCommentDetector = - new(@"^((//)|(')|(/\*))\s*lang(uage)?\s*=\s*regex(p)?\b((\s*,\s*)(? - private class FindLiteralsProgressAdapter : IStreamingFindLiteralReferencesProgress + private sealed class FindLiteralsProgressAdapter : IStreamingFindLiteralReferencesProgress { private readonly IFindUsagesContext _context; private readonly DefinitionItem _definition; - private readonly ClassificationOptions _classificationOptions; public IStreamingProgressTracker ProgressTracker => _context.ProgressTracker; public FindLiteralsProgressAdapter( - IFindUsagesContext context, DefinitionItem definition, ClassificationOptions classificationOptions) + IFindUsagesContext context, DefinitionItem definition) { _context = context; _definition = definition; - _classificationOptions = classificationOptions; } public async ValueTask OnReferenceFoundAsync(Document document, TextSpan span, CancellationToken cancellationToken) { + // TODO: + // var options = await _context.GetOptionsAsync(document.Project.Language, cancellationToken).ConfigureAwait(false); + var classificationOptions = ClassificationOptions.From(document.Project); + var documentSpan = await ClassifiedSpansAndHighlightSpanFactory.GetClassifiedDocumentSpanAsync( - document, span, _classificationOptions, cancellationToken).ConfigureAwait(false); + document, span, classificationOptions, cancellationToken).ConfigureAwait(false); + await _context.OnReferenceFoundAsync( new SourceReferenceItem(_definition, documentSpan, SymbolUsageInfo.None), cancellationToken).ConfigureAwait(false); } @@ -52,7 +56,7 @@ await _context.OnReferenceFoundAsync( /// /// Forwards IFindReferencesProgress calls to an IFindUsagesContext instance. /// - private class FindReferencesProgressAdapter : IStreamingFindReferencesProgress + private sealed class FindReferencesProgressAdapter : IStreamingFindReferencesProgress { private readonly Solution _solution; private readonly IFindUsagesContext _context; @@ -124,7 +128,9 @@ public async ValueTask OnReferenceFoundAsync(SymbolGroup group, ISymbol definiti { var definitionItem = await GetDefinitionItemAsync(group, cancellationToken).ConfigureAwait(false); var referenceItem = await location.TryCreateSourceReferenceItemAsync( - definitionItem, includeHiddenLocations: false, + _context, + definitionItem, + includeHiddenLocations: false, cancellationToken).ConfigureAwait(false); if (referenceItem != null) diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.cs similarity index 75% rename from src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs rename to src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.cs index 7cf32892ba986..8e9bc8eb5ea90 100644 --- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs +++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; - -namespace Microsoft.CodeAnalysis.Editor.FindUsages +namespace Microsoft.CodeAnalysis.FindUsages { internal abstract partial class AbstractFindUsagesService : IFindUsagesService, IFindUsagesLSPService { diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs similarity index 86% rename from src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs rename to src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs index adee674dd0c9c..45a50f3e08c94 100644 --- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs +++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindImplementations.cs @@ -15,12 +15,12 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.FindUsages +namespace Microsoft.CodeAnalysis.FindUsages { internal abstract partial class AbstractFindUsagesService { public async Task FindImplementationsAsync( - Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) + IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) { // If this is a symbol from a metadata-as-source project, then map that symbol back to a symbol in the primary workspace. var symbolAndProjectOpt = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync( @@ -28,17 +28,17 @@ public async Task FindImplementationsAsync( if (symbolAndProjectOpt == null) { await context.ReportMessageAsync( - EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret, cancellationToken).ConfigureAwait(false); + FeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret, cancellationToken).ConfigureAwait(false); return; } var symbolAndProject = symbolAndProjectOpt.Value; await FindImplementationsAsync( - symbolAndProject.symbol, symbolAndProject.project, context, cancellationToken).ConfigureAwait(false); + context, symbolAndProject.symbol, symbolAndProject.project, cancellationToken).ConfigureAwait(false); } public static async Task FindImplementationsAsync( - ISymbol symbol, Project project, IFindUsagesContext context, CancellationToken cancellationToken) + IFindUsagesContext context, ISymbol symbol, Project project, CancellationToken cancellationToken) { var solution = project.Solution; var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); @@ -68,7 +68,7 @@ private static async Task FindImplementationsInCurrentProcessAsync( ISymbol symbol, Project project, IFindUsagesContext context, CancellationToken cancellationToken) { await context.SetSearchTitleAsync( - string.Format(EditorFeaturesResources._0_implementations, + string.Format(FeaturesResources._0_implementations, FindUsagesHelpers.GetDisplayName(symbol)), cancellationToken).ConfigureAwait(false); @@ -77,7 +77,7 @@ await context.SetSearchTitleAsync( if (implementations.IsEmpty) { - await context.ReportMessageAsync(EditorFeaturesResources.The_symbol_has_no_implementations, cancellationToken).ConfigureAwait(false); + await context.ReportMessageAsync(FeaturesResources.The_symbol_has_no_implementations, cancellationToken).ConfigureAwait(false); return; } @@ -110,7 +110,7 @@ private static async Task> FindSourceImplementationsAsyn foreach (var linkedSymbol in linkedSymbols) { - var implementations = await FindSourceImplementationsWorkerAsync( + var implementations = await FindImplementationsWorkerAsync( solution, linkedSymbol, cancellationToken).ConfigureAwait(false); foreach (var implementation in implementations) { @@ -125,8 +125,7 @@ static bool AddedAllLocations(ISymbol implementation, HashSet<(string filePath, { foreach (var location in implementation.Locations) { - Contract.ThrowIfFalse(location.IsInSource); - if (!seenLocations.Add((location.SourceTree.FilePath, location.SourceSpan))) + if (location.IsInSource && !seenLocations.Add((location.SourceTree.FilePath, location.SourceSpan))) return false; } @@ -134,26 +133,26 @@ static bool AddedAllLocations(ISymbol implementation, HashSet<(string filePath, } } - private static async Task> FindSourceImplementationsWorkerAsync( + private static async Task> FindImplementationsWorkerAsync( Solution solution, ISymbol symbol, CancellationToken cancellationToken) { var implementations = await FindSourceAndMetadataImplementationsAsync(solution, symbol, cancellationToken).ConfigureAwait(false); - var sourceImplementations = new HashSet(implementations.Where(s => s.IsFromSource()).Select(s => s.OriginalDefinition)); + var result = new HashSet(implementations.Select(s => s.OriginalDefinition)); // For members, if we've found overrides of the original symbol, then filter out any abstract // members these inherit from. The user has asked for literal implementations, and in the case // of an override, including the abstract as well isn't helpful. - var overrides = sourceImplementations.Where(s => s.IsOverride).ToImmutableArray(); + var overrides = result.Where(s => s.IsOverride).ToImmutableArray(); foreach (var ov in overrides) { for (var overridden = ov.GetOverriddenMember(); overridden != null; overridden = overridden.GetOverriddenMember()) { if (overridden.IsAbstract) - sourceImplementations.Remove(overridden.OriginalDefinition); + result.Remove(overridden.OriginalDefinition); } } - return sourceImplementations.ToImmutableArray(); + return result.ToImmutableArray(); } private static async Task> FindSourceAndMetadataImplementationsAsync( diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindReferences.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs similarity index 90% rename from src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindReferences.cs rename to src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs index c2d540945713f..7d67940e9cbc3 100644 --- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindReferences.cs +++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs @@ -11,22 +11,23 @@ using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.FindUsages +namespace Microsoft.CodeAnalysis.FindUsages { internal abstract partial class AbstractFindUsagesService { async Task IFindUsagesService.FindReferencesAsync( - Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) + IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) { var definitionTrackingContext = new DefinitionTrackingContext(context); await FindLiteralOrSymbolReferencesAsync( - document, position, definitionTrackingContext, cancellationToken).ConfigureAwait(false); + definitionTrackingContext, document, position, cancellationToken).ConfigureAwait(false); // After the FAR engine is done call into any third party extensions to see // if they want to add results. @@ -38,23 +39,23 @@ await FindLiteralOrSymbolReferencesAsync( } Task IFindUsagesLSPService.FindReferencesAsync( - Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) + IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) { // We don't need to get third party definitions when finding references in LSP. // Currently, 3rd party definitions = XAML definitions, and XAML will provide // references via LSP instead of hooking into Roslyn. // This also means that we don't need to be on the UI thread. return FindLiteralOrSymbolReferencesAsync( - document, position, new DefinitionTrackingContext(context), cancellationToken); + new DefinitionTrackingContext(context), document, position, cancellationToken); } private static async Task FindLiteralOrSymbolReferencesAsync( - Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) + IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) { // First, see if we're on a literal. If so search for literals in the solution with // the same value. var found = await TryFindLiteralReferencesAsync( - document, position, context, cancellationToken).ConfigureAwait(false); + context, document, position, cancellationToken).ConfigureAwait(false); if (found) { return; @@ -62,7 +63,7 @@ private static async Task FindLiteralOrSymbolReferencesAsync( // Wasn't a literal. Try again as a symbol. await FindSymbolReferencesAsync( - document, position, context, cancellationToken).ConfigureAwait(false); + context, document, position, cancellationToken).ConfigureAwait(false); } private static async Task> GetThirdPartyDefinitionsAsync( @@ -84,7 +85,7 @@ private static async Task> GetThirdPartyDefinitio } private static async Task FindSymbolReferencesAsync( - Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) + IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -108,7 +109,7 @@ public static async Task FindSymbolReferencesAsync( IFindUsagesContext context, ISymbol symbol, Project project, CancellationToken cancellationToken) { await context.SetSearchTitleAsync( - string.Format(EditorFeaturesResources._0_references, + string.Format(FeaturesResources._0_references, FindUsagesHelpers.GetDisplayName(symbol)), cancellationToken).ConfigureAwait(false); @@ -165,7 +166,7 @@ private static Task FindReferencesInCurrentProcessAsync( } private static async Task TryFindLiteralReferencesAsync( - Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) + IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -212,7 +213,7 @@ private static async Task TryFindLiteralReferencesAsync( title = title.Substring(0, 10) + "..."; } - var searchTitle = string.Format(EditorFeaturesResources._0_references, title); + var searchTitle = string.Format(FeaturesResources._0_references, title); await context.SetSearchTitleAsync(searchTitle, cancellationToken).ConfigureAwait(false); var solution = document.Project.Solution; @@ -225,8 +226,7 @@ private static async Task TryFindLiteralReferencesAsync( await context.OnDefinitionFoundAsync(definition, cancellationToken).ConfigureAwait(false); - var classificationOptions = ClassificationOptions.From(document.Project); - var progressAdapter = new FindLiteralsProgressAdapter(context, definition, classificationOptions); + var progressAdapter = new FindLiteralsProgressAdapter(context, definition); // Now call into the underlying FAR engine to find reference. The FAR // engine will push results into the 'progress' instance passed into it. diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs index ec13d642ee034..eca8e41f33e77 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs @@ -29,88 +29,67 @@ public DefaultDefinitionItem( ImmutableArray nameDisplayParts, ImmutableArray originationParts, ImmutableArray sourceSpans, - ImmutableDictionary properties, - ImmutableDictionary displayableProperties, + ImmutableDictionary? properties, + ImmutableDictionary? displayableProperties, bool displayIfNoReferences) : base(tags, displayParts, nameDisplayParts, originationParts, sourceSpans, properties, displayableProperties, displayIfNoReferences) { } - [Obsolete("Override CanNavigateToAsync instead", error: false)] - public override bool CanNavigateTo(Workspace workspace, CancellationToken cancellationToken) - => throw new NotImplementedException(); - - [Obsolete("Override TryNavigateToAsync instead", error: false)] - public override bool TryNavigateTo(Workspace workspace, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) - => throw new NotImplementedException(); - public sealed override async Task CanNavigateToAsync(Workspace workspace, CancellationToken cancellationToken) { if (Properties.ContainsKey(NonNavigable)) return false; if (Properties.TryGetValue(MetadataSymbolKey, out var symbolKey)) - return await CanNavigateToMetadataSymbolAsync(workspace, symbolKey).ConfigureAwait(false); + { + var (_, symbol) = await TryResolveSymbolInCurrentSolutionAsync(workspace, symbolKey, cancellationToken).ConfigureAwait(false); + return symbol is { Kind: not SymbolKind.Namespace }; + } - return await this.SourceSpans[0].CanNavigateToAsync(cancellationToken).ConfigureAwait(false); + return await SourceSpans[0].CanNavigateToAsync(cancellationToken).ConfigureAwait(false); } - public sealed override async Task TryNavigateToAsync(Workspace workspace, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) + public sealed override async Task TryNavigateToAsync(Workspace workspace, NavigationOptions options, CancellationToken cancellationToken) { if (Properties.ContainsKey(NonNavigable)) return false; if (Properties.TryGetValue(MetadataSymbolKey, out var symbolKey)) - return await TryNavigateToMetadataSymbolAsync(workspace, symbolKey).ConfigureAwait(false); - - return await this.SourceSpans[0].TryNavigateToAsync(showInPreviewTab, activateTab, cancellationToken).ConfigureAwait(false); - } - - public DetachedDefinitionItem Detach() - => new(Tags, DisplayParts, NameDisplayParts, OriginationParts, SourceSpans, Properties, DisplayableProperties, DisplayIfNoReferences); - - private Task CanNavigateToMetadataSymbolAsync(Workspace workspace, string symbolKey) - => TryNavigateToMetadataSymbolAsync(workspace, symbolKey, action: (symbol, project, service) => true); - - private Task TryNavigateToMetadataSymbolAsync(Workspace workspace, string symbolKey) - { - return TryNavigateToMetadataSymbolAsync( - workspace, symbolKey, - action: (symbol, project, service) => + { + var (project, symbol) = await TryResolveSymbolInCurrentSolutionAsync(workspace, symbolKey, cancellationToken).ConfigureAwait(false); + if (symbol is { Kind: not SymbolKind.Namespace }) { - return service.TryNavigateToSymbol( - symbol, project, project.Solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true)); - }); - } + Contract.ThrowIfNull(project); + + var navigationService = workspace.Services.GetRequiredService(); + return navigationService.TryNavigateToSymbol(symbol, project, options with { PreferProvisionalTab = true }, cancellationToken); + } - private async Task TryNavigateToMetadataSymbolAsync( - Workspace workspace, string symbolKey, Func action) - { - var projectAndSymbol = await TryResolveSymbolInCurrentSolutionAsync(workspace, symbolKey).ConfigureAwait(false); - if (projectAndSymbol is not (var project, { Kind: not SymbolKind.Namespace } symbol)) - { return false; } - var navigationService = workspace.Services.GetRequiredService(); - return action(symbol, project, navigationService); + return await SourceSpans[0].TryNavigateToAsync(options, cancellationToken).ConfigureAwait(false); } - private async ValueTask<(Project project, ISymbol? symbol)?> TryResolveSymbolInCurrentSolutionAsync(Workspace workspace, string symbolKey) + public DetachedDefinitionItem Detach() + => new(Tags, DisplayParts, NameDisplayParts, OriginationParts, SourceSpans, Properties, DisplayableProperties, DisplayIfNoReferences); + + private async ValueTask<(Project? project, ISymbol? symbol)> TryResolveSymbolInCurrentSolutionAsync(Workspace workspace, string symbolKey, CancellationToken cancellationToken) { if (!Properties.TryGetValue(MetadataSymbolOriginatingProjectIdGuid, out var projectIdGuid) || !Properties.TryGetValue(MetadataSymbolOriginatingProjectIdDebugName, out var projectDebugName)) { - return null; + return default; } var project = workspace.CurrentSolution.GetProject(ProjectId.CreateFromSerialized(Guid.Parse(projectIdGuid), projectDebugName)); if (project == null) - return null; + return default; - var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None).ConfigureAwait(false); - var symbol = SymbolKey.ResolveString(symbolKey, compilation).Symbol; + var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + var symbol = SymbolKey.ResolveString(symbolKey, compilation, cancellationToken: cancellationToken).Symbol; return (project, symbol); } } diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs index 06c21ede36a09..2f30490dbabb0 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs @@ -2,13 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; +using System.ComponentModel; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.FindSymbols.Finders; +using Microsoft.CodeAnalysis.MetadataAsSource; +using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.Tags; using Roslyn.Utilities; @@ -118,7 +120,7 @@ protected DefinitionItem( ImmutableArray nameDisplayParts, ImmutableArray originationParts, ImmutableArray sourceSpans, - ImmutableDictionary properties, + ImmutableDictionary? properties, bool displayIfNoReferences) : this( tags, @@ -138,8 +140,8 @@ protected DefinitionItem( ImmutableArray nameDisplayParts, ImmutableArray originationParts, ImmutableArray sourceSpans, - ImmutableDictionary properties, - ImmutableDictionary displayableProperties, + ImmutableDictionary? properties, + ImmutableDictionary? displayableProperties, bool displayIfNoReferences) { Tags = tags; @@ -158,24 +160,23 @@ protected DefinitionItem( } } - [Obsolete("Override CanNavigateToAsync instead", error: false)] - public abstract bool CanNavigateTo(Workspace workspace, CancellationToken cancellationToken); - [Obsolete("Override TryNavigateToAsync instead", error: false)] - public abstract bool TryNavigateTo(Workspace workspace, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken); +#pragma warning disable CS0612 // Type or member is obsolete - TypeScript + [Obsolete] + public virtual bool CanNavigateTo(Workspace workspace, CancellationToken cancellationToken) => false; + + [Obsolete] + public virtual bool TryNavigateTo(Workspace workspace, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) => false; public virtual Task CanNavigateToAsync(Workspace workspace, CancellationToken cancellationToken) - { -#pragma warning disable CS0618 // Type or member is obsolete - return Task.FromResult(CanNavigateTo(workspace, cancellationToken)); -#pragma warning restore CS0618 // Type or member is obsolete - } + => Task.FromResult(CanNavigateTo(workspace, cancellationToken)); + [Obsolete] public virtual Task TryNavigateToAsync(Workspace workspace, bool showInPreviewTab, bool activateTab, CancellationToken cancellationToken) - { -#pragma warning disable CS0618 // Type or member is obsolete - return Task.FromResult(TryNavigateTo(workspace, showInPreviewTab, activateTab, cancellationToken)); -#pragma warning restore CS0618 // Type or member is obsolete - } + => Task.FromResult(TryNavigateTo(workspace, showInPreviewTab, activateTab, cancellationToken)); + + public virtual Task TryNavigateToAsync(Workspace workspace, NavigationOptions options, CancellationToken cancellationToken) + => TryNavigateToAsync(workspace, options.PreferProvisionalTab, options.ActivateTab, cancellationToken); +#pragma warning restore public static DefinitionItem Create( ImmutableArray tags, @@ -207,7 +208,7 @@ public static DefinitionItem Create( ImmutableArray displayParts, ImmutableArray sourceSpans, ImmutableArray nameDisplayParts = default, - ImmutableDictionary properties = null, + ImmutableDictionary? properties = null, bool displayIfNoReferences = true) { return Create(tags, displayParts, sourceSpans, nameDisplayParts, properties, ImmutableDictionary.Empty, displayIfNoReferences); @@ -218,8 +219,8 @@ public static DefinitionItem Create( ImmutableArray displayParts, ImmutableArray sourceSpans, ImmutableArray nameDisplayParts = default, - ImmutableDictionary properties = null, - ImmutableDictionary displayableProperties = null, + ImmutableDictionary? properties = null, + ImmutableDictionary? displayableProperties = null, bool displayIfNoReferences = true) { if (sourceSpans.Length == 0) @@ -242,7 +243,7 @@ internal static DefinitionItem CreateMetadataDefinition( ImmutableArray nameDisplayParts, Solution solution, ISymbol symbol, - ImmutableDictionary properties = null, + ImmutableDictionary? properties = null, bool displayIfNoReferences = true) { properties ??= ImmutableDictionary.Empty; @@ -254,7 +255,15 @@ internal static DefinitionItem CreateMetadataDefinition( properties = properties.Add(MetadataSymbolKey, symbolKey) .Add(MetadataSymbolOriginatingProjectIdGuid, projectId.Id.ToString()) - .Add(MetadataSymbolOriginatingProjectIdDebugName, projectId.DebugName); + .Add(MetadataSymbolOriginatingProjectIdDebugName, projectId.DebugName ?? ""); + + // Find the highest level containing type to show as the "file name". For metadata locations + // that come from embedded source or SourceLink this could be wrong, as there is no reason + // to assume a type is defined in a filename that matches, but its _way_ too expensive + // to try to find the right answer. For metadata-as-source locations though, it will be the same + // as the synthesized filename, so will make sense in the majority of cases. + var containingTypeName = MetadataAsSourceHelpers.GetTopLevelContainingNamedType(symbol).Name; + properties = properties.Add(AbstractReferenceFinder.ContainingTypeInfoPropertyName, containingTypeName); var originationParts = GetOriginationParts(symbol); return new DefaultDefinitionItem( @@ -281,7 +290,7 @@ public static DefinitionItem CreateNonNavigableItem( ImmutableArray tags, ImmutableArray displayParts, ImmutableArray originationParts = default, - ImmutableDictionary properties = null, + ImmutableDictionary? properties = null, bool displayIfNoReferences = true) { properties ??= ImmutableDictionary.Empty; diff --git a/src/Features/Core/Portable/FindUsages/ExternalScope.cs b/src/Features/Core/Portable/FindUsages/ExternalScope.cs index 4f4e0416f90cb..55b3fb4e3944b 100644 --- a/src/Features/Core/Portable/FindUsages/ExternalScope.cs +++ b/src/Features/Core/Portable/FindUsages/ExternalScope.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - namespace Microsoft.CodeAnalysis.FindUsages { internal enum ExternalScope diff --git a/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs b/src/Features/Core/Portable/FindUsages/FindUsagesContext.cs similarity index 83% rename from src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs rename to src/Features/Core/Portable/FindUsages/FindUsagesContext.cs index 2f135234aadc2..64ccc1393cef3 100644 --- a/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs +++ b/src/Features/Core/Portable/FindUsages/FindUsagesContext.cs @@ -4,7 +4,9 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Utilities; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindUsages { @@ -13,7 +15,11 @@ internal abstract class FindUsagesContext : IFindUsagesContext public IStreamingProgressTracker ProgressTracker { get; } protected FindUsagesContext() - => this.ProgressTracker = new StreamingProgressTracker(this.ReportProgressAsync); + { + ProgressTracker = new StreamingProgressTracker(ReportProgressAsync); + } + + public abstract ValueTask GetOptionsAsync(string language, CancellationToken cancellationToken); public virtual ValueTask ReportMessageAsync(string message, CancellationToken cancellationToken) => default; diff --git a/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs b/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs index fb6da25c517b7..818f39973d2c7 100644 --- a/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs +++ b/src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SymbolMapping; -namespace Microsoft.CodeAnalysis.Editor.FindUsages +namespace Microsoft.CodeAnalysis.FindUsages { internal static class FindUsagesHelpers { diff --git a/src/Features/Core/Portable/FindUsages/FindUsagesOptions.cs b/src/Features/Core/Portable/FindUsages/FindUsagesOptions.cs new file mode 100644 index 0000000000000..99c48595a6e8b --- /dev/null +++ b/src/Features/Core/Portable/FindUsages/FindUsagesOptions.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; +using Microsoft.CodeAnalysis.Classification; + +namespace Microsoft.CodeAnalysis.FindUsages +{ + [DataContract] + internal readonly record struct FindUsagesOptions( + [property: DataMember(Order = 0)] ClassificationOptions ClassificationOptions) + { + public FindUsagesOptions() + : this(ClassificationOptions.Default) + { + } + + public static readonly FindUsagesOptions Default = new(); + } +} diff --git a/src/EditorFeatures/Core/FindUsages/IDefinitionsAndReferencesFactory.cs b/src/Features/Core/Portable/FindUsages/IDefinitionsAndReferencesFactory.cs similarity index 94% rename from src/EditorFeatures/Core/FindUsages/IDefinitionsAndReferencesFactory.cs rename to src/Features/Core/Portable/FindUsages/IDefinitionsAndReferencesFactory.cs index 805b7382eb81d..3241ee68cbfac 100644 --- a/src/EditorFeatures/Core/FindUsages/IDefinitionsAndReferencesFactory.cs +++ b/src/Features/Core/Portable/FindUsages/IDefinitionsAndReferencesFactory.cs @@ -13,14 +13,14 @@ using Microsoft.CodeAnalysis.Features.RQName; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindSymbols.Finders; -using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.FindUsages +namespace Microsoft.CodeAnalysis.FindUsages { using static FindUsagesHelpers; @@ -77,7 +77,7 @@ public static Task ToNonClassifiedDefinitionItemAsync( { return ToDefinitionItemAsync( definition, solution, isPrimary: false, includeHiddenLocations, includeClassifiedSpans: false, - options: FindReferencesSearchOptions.Default.With(unidirectionalHierarchyCascade: true), cancellationToken: cancellationToken); + options: FindReferencesSearchOptions.Default with { UnidirectionalHierarchyCascade = true }, cancellationToken); } public static Task ToClassifiedDefinitionItemAsync( @@ -226,6 +226,9 @@ private static ImmutableDictionary GetProperties(ISymbol definit public static async Task TryCreateSourceReferenceItemAsync( this ReferenceLocation referenceLocation, +#pragma warning disable IDE0060 // Remove unused parameter TODO + IFindUsagesContext context, +#pragma warning restore IDE0060 // Remove unused parameter DefinitionItem definitionItem, bool includeHiddenLocations, CancellationToken cancellationToken) @@ -241,10 +244,13 @@ private static ImmutableDictionary GetProperties(ISymbol definit var document = referenceLocation.Document; var sourceSpan = location.SourceSpan; - var options = ClassificationOptions.From(document.Project); + + // TODO: + // var options = await context.GetOptionsAsync(document.Project.Language, cancellationToken).ConfigureAwait(false); + var classificationOptions = ClassificationOptions.From(document.Project); var documentSpan = await ClassifiedSpansAndHighlightSpanFactory.GetClassifiedDocumentSpanAsync( - document, sourceSpan, options, cancellationToken).ConfigureAwait(false); + document, sourceSpan, classificationOptions, cancellationToken).ConfigureAwait(false); return new SourceReferenceItem(definitionItem, documentSpan, referenceLocation.SymbolUsageInfo, referenceLocation.AdditionalProperties); } diff --git a/src/Features/Core/Portable/FindUsages/IFindUsagesContext.cs b/src/Features/Core/Portable/FindUsages/IFindUsagesContext.cs index 6fc2029e2f948..58ea91b8667da 100644 --- a/src/Features/Core/Portable/FindUsages/IFindUsagesContext.cs +++ b/src/Features/Core/Portable/FindUsages/IFindUsagesContext.cs @@ -17,6 +17,11 @@ internal interface IFindUsagesContext /// IStreamingProgressTracker ProgressTracker { get; } + /// + /// Get for specified language. + /// + ValueTask GetOptionsAsync(string language, CancellationToken cancellationToken); + /// /// Report a failure message to be displayed to the user. This will be reported if the find operation returns /// no results. diff --git a/src/EditorFeatures/Core/FindUsages/IFindUsagesLSPService.cs b/src/Features/Core/Portable/FindUsages/IFindUsagesLSPService.cs similarity index 72% rename from src/EditorFeatures/Core/FindUsages/IFindUsagesLSPService.cs rename to src/Features/Core/Portable/FindUsages/IFindUsagesLSPService.cs index 5533dd10c364a..ef79deb5307fa 100644 --- a/src/EditorFeatures/Core/FindUsages/IFindUsagesLSPService.cs +++ b/src/Features/Core/Portable/FindUsages/IFindUsagesLSPService.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.CodeAnalysis.Editor.FindUsages +namespace Microsoft.CodeAnalysis.FindUsages { internal interface IFindUsagesLSPService : ILanguageService { @@ -15,12 +15,12 @@ internal interface IFindUsagesLSPService : ILanguageService /// Finds the references for the symbol at the specific position in the document, /// pushing the results into the context instance. /// - Task FindReferencesAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken); + Task FindReferencesAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken); /// /// Finds the implementations for the symbol at the specific position in the document, /// pushing the results into the context instance. /// - Task FindImplementationsAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken); + Task FindImplementationsAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken); } } diff --git a/src/EditorFeatures/Core/FindUsages/IFindUsagesService.cs b/src/Features/Core/Portable/FindUsages/IFindUsagesService.cs similarity index 72% rename from src/EditorFeatures/Core/FindUsages/IFindUsagesService.cs rename to src/Features/Core/Portable/FindUsages/IFindUsagesService.cs index e6c247e4bd999..4a782b8a24378 100644 --- a/src/EditorFeatures/Core/FindUsages/IFindUsagesService.cs +++ b/src/Features/Core/Portable/FindUsages/IFindUsagesService.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.CodeAnalysis.Editor.FindUsages +namespace Microsoft.CodeAnalysis.FindUsages { internal interface IFindUsagesService : ILanguageService { @@ -15,12 +15,12 @@ internal interface IFindUsagesService : ILanguageService /// Finds the references for the symbol at the specific position in the document, /// pushing the results into the context instance. /// - Task FindReferencesAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken); + Task FindReferencesAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken); /// /// Finds the implementations for the symbol at the specific position in the document, /// pushing the results into the context instance. /// - Task FindImplementationsAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken); + Task FindImplementationsAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs index 781a93e532b9a..990f068098c3f 100644 --- a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs +++ b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs @@ -22,6 +22,7 @@ internal interface IRemoteFindUsagesService { internal interface ICallback { + ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken); ValueTask AddItemsAsync(RemoteServiceCallbackId callbackId, int count, CancellationToken cancellationToken); ValueTask ItemsCompletedAsync(RemoteServiceCallbackId callbackId, int count, CancellationToken cancellationToken); ValueTask ReportMessageAsync(RemoteServiceCallbackId callbackId, string message, CancellationToken cancellationToken); @@ -57,6 +58,9 @@ public FindUsagesServerCallbackDispatcher() private new FindUsagesServerCallback GetCallback(RemoteServiceCallbackId callbackId) => (FindUsagesServerCallback)base.GetCallback(callbackId); + public ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken) + => GetCallback(callbackId).GetOptionsAsync(language, cancellationToken); + public ValueTask AddItemsAsync(RemoteServiceCallbackId callbackId, int count, CancellationToken cancellationToken) => GetCallback(callbackId).AddItemsAsync(count, cancellationToken); @@ -91,6 +95,9 @@ public FindUsagesServerCallback(Solution solution, IFindUsagesContext context) _context = context; } + public ValueTask GetOptionsAsync(string language, CancellationToken cancellationToken) + => _context.GetOptionsAsync(language, cancellationToken); + public ValueTask AddItemsAsync(int count, CancellationToken cancellationToken) => _context.ProgressTracker.AddItemsAsync(count, cancellationToken); diff --git a/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs b/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs index ab129104e169e..8be7bfe176e3e 100644 --- a/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs +++ b/src/Features/Core/Portable/Formatting/AbstractNewDocumentFormattingService.cs @@ -7,8 +7,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Formatting { @@ -41,7 +43,16 @@ public async Task FormatNewDocumentAsync(Document document, Document? // other, so this shouldn't cause problems. try { + // First we ask the provider to "format" the document. This could be formatting in terms + // of adjusting block scopes to file scopes etc., but it could also be more akin to fixers + // like adding access modifiers, or adding .ConfigureAwait() calls etc. document = await provider.FormatNewDocumentAsync(document, hintDocument, cancellationToken).ConfigureAwait(false); + + // Now that the above has changed the document, we use the code action engine to clean up the document + // before we call the next provider, otherwise they might not see things as they are meant to be. + // Because formatting providers often re-use code fix logic, they are often written assuming this will + // happen. + document = await CodeAction.CleanupDocumentAsync(document, cancellationToken).ConfigureAwait(false); } catch (Exception ex) when (FatalError.ReportAndCatchUnlessCanceled(ex, cancellationToken, ErrorSeverity.General)) { diff --git a/src/Features/Core/Portable/Formatting/FormattingCodeFixProvider.cs b/src/Features/Core/Portable/Formatting/FormattingCodeFixProvider.cs index 961e87a83bdb5..ba339b3690055 100644 --- a/src/Features/Core/Portable/Formatting/FormattingCodeFixProvider.cs +++ b/src/Features/Core/Portable/Formatting/FormattingCodeFixProvider.cs @@ -46,9 +46,9 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) private static async Task FixOneAsync(CodeFixContext context, Diagnostic diagnostic, CancellationToken cancellationToken) { - var options = await context.Document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var options = await SyntaxFormattingOptions.FromDocumentAsync(context.Document, cancellationToken).ConfigureAwait(false); var tree = await context.Document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var formattedTree = await FormattingCodeFixHelper.FixOneAsync(tree, context.Document.Project.Solution.Workspace, options, diagnostic, cancellationToken).ConfigureAwait(false); + var formattedTree = await FormattingCodeFixHelper.FixOneAsync(tree, context.Document.Project.Solution.Workspace.Services, options, diagnostic, cancellationToken).ConfigureAwait(false); return context.Document.WithSyntaxRoot(await formattedTree.GetRootAsync(cancellationToken).ConfigureAwait(false)); } diff --git a/src/Features/Core/Portable/Formatting/FormattingDiagnosticAnalyzer.cs b/src/Features/Core/Portable/Formatting/FormattingDiagnosticAnalyzer.cs index ab0ee07a389fb..61acf0f0ccee5 100644 --- a/src/Features/Core/Portable/Formatting/FormattingDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/Formatting/FormattingDiagnosticAnalyzer.cs @@ -38,10 +38,10 @@ private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context) var tree = context.Tree; var cancellationToken = context.CancellationToken; + var optionSet = context.Options.GetAnalyzerOptionSet(tree, cancellationToken); + var options = SyntaxFormattingOptions.Create(optionSet, workspaceAnalyzerOptions.Services, tree.Options.Language); - var options = context.Options.GetAnalyzerOptionSet(tree, cancellationToken); - var workspace = workspaceAnalyzerOptions.Services.Workspace; - FormattingAnalyzerHelper.AnalyzeSyntaxTree(context, workspace, Descriptor, options); + FormattingAnalyzerHelper.AnalyzeSyntaxTree(context, workspaceAnalyzerOptions.Services, Descriptor, options); } } } diff --git a/src/Features/Core/Portable/Formatting/IFormattingInteractionService.cs b/src/Features/Core/Portable/Formatting/IFormattingInteractionService.cs index 5b9880cab2767..84296fa0cb7c2 100644 --- a/src/Features/Core/Portable/Formatting/IFormattingInteractionService.cs +++ b/src/Features/Core/Portable/Formatting/IFormattingInteractionService.cs @@ -22,7 +22,7 @@ internal interface IFormattingInteractionService : ILanguageService /// True if this service would like to format the document based on the user typing the /// provided character. /// - bool SupportsFormattingOnTypedCharacter(Document document, char ch); + bool SupportsFormattingOnTypedCharacter(Document document, AutoFormattingOptions options, char ch); /// /// Returns the text changes necessary to format the document. If "textSpan" is provided, diff --git a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs index 7ba03575fce08..9fb65c4415f99 100644 --- a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs +++ b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs @@ -63,9 +63,10 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } + var hideAdvancedMembers = context.Options.HideAdvancedMembers; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var matchingTypes = await GetMatchingTypesAsync(document, semanticModel, node, cancellationToken).ConfigureAwait(false); + var matchingTypes = await GetMatchingTypesAsync(document, semanticModel, node, hideAdvancedMembers, cancellationToken).ConfigureAwait(false); var matchingNamespaces = await GetMatchingNamespacesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false); if (matchingTypes.IsEmpty && matchingNamespaces.IsEmpty) @@ -147,7 +148,7 @@ private async Task ProcessNodeAsync(Document document, SyntaxNode node } private async Task> GetMatchingTypesAsync( - Document document, SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken) + Document document, SemanticModel semanticModel, SyntaxNode node, bool hideAdvancedMembers, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -171,8 +172,6 @@ private async Task> GetMatchingTypesAsync( symbols = symbols.Concat(attributeSymbols); } - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var hideAdvancedMembers = options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers); var editorBrowserInfo = new EditorBrowsableInfo(semanticModel.Compilation); var validSymbols = symbols diff --git a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs index 852139e23f41b..9ccad19ba7c4c 100644 --- a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs @@ -136,7 +136,6 @@ private static async Task GenerateComparisonOperatorsAsync( INamedTypeSymbol comparableType, CancellationToken cancellationToken) { - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var containingType = (INamedTypeSymbol)semanticModel.GetRequiredDeclaredSymbol(typeDeclaration, cancellationToken); @@ -149,14 +148,9 @@ private static async Task GenerateComparisonOperatorsAsync( generator, semanticModel.Compilation, containingType, comparableType, GenerateLeftExpression(generator, comparableType, compareMethod)); - return await codeGenService.AddMembersAsync( - document.Project.Solution, - containingType, - operators, - new CodeGenerationOptions( - contextLocation: typeDeclaration.GetLocation(), - options: options, - parseOptions: typeDeclaration.SyntaxTree.Options), cancellationToken).ConfigureAwait(false); + var context = new CodeGenerationContext(contextLocation: typeDeclaration.GetLocation()); + + return await codeGenService.AddMembersAsync(document.Project.Solution, containingType, operators, context, cancellationToken).ConfigureAwait(false); } private static SyntaxNode GenerateLeftExpression( diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs index 77d7848fce439..8ab0ee4c71b32 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs @@ -98,7 +98,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke parameters: _state.Parameters, statements: statements, thisConstructorArguments: thisConstructorArguments), - new CodeGenerationOptions( + new CodeGenerationContext( contextLocation: syntaxTree.GetLocation(_state.TextSpan), afterThisLocation: afterThisLocation), cancellationToken: cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs index 57f807e53a2d2..2505655e2a6a9 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs @@ -77,7 +77,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke _document.Project.Solution, _state.ContainingType, members, - new CodeGenerationOptions( + new CodeGenerationContext( contextLocation: syntaxTree.GetLocation(_state.TextSpan), afterThisLocation: afterThisLocation), cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs index 37cd7f4cfdf9f..123ee3c1c7e19 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs @@ -44,7 +44,8 @@ protected override async Task GetChangedDocumentAsync(CancellationToke _document.Project.Solution, _state.ClassType, _constructors.Select(CreateConstructorDefinition), - cancellationToken: cancellationToken).ConfigureAwait(false); + CodeGenerationContext.Default, + cancellationToken).ConfigureAwait(false); return result; } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs index 0bd001d809b77..7af524450a859 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs @@ -102,6 +102,14 @@ private static bool FixesError(INamedTypeSymbol classType, INamedTypeSymbol base // and let the code fix provider handle it instead. return true; } + + // If this is a struct that has initializers, but is missing a parameterless constructor then we are fixing + // an error (CS8983) but since this is the only scenario where we support structs we don't need to actually + // check for anything else. + if (classType.TypeKind == TypeKind.Struct) + { + return true; + } } return false; diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs index d55ce6dc559fd..431e46e3252e3 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; @@ -80,10 +81,9 @@ protected override async Task GetChangedDocumentAsync(CancellationToke await AddOperatorsAsync(methods, cancellationToken).ConfigureAwait(false); } - var options = await _document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var newTypeDeclaration = CodeGenerator.AddMemberDeclarations( - _typeDeclaration, methods, _document.Project.Solution.Workspace, - new CodeGenerationOptions(options: options)); + var codeGenerator = _document.GetRequiredLanguageService(); + var options = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, _document, cancellationToken).ConfigureAwait(false); + var newTypeDeclaration = codeGenerator.AddMembers(_typeDeclaration, methods, options, cancellationToken); if (constructedTypeToImplement is object) { @@ -125,11 +125,10 @@ protected override async Task GetChangedDocumentAsync(CancellationToke private async Task UpdateDocumentAndAddImportsAsync(SyntaxNode oldType, SyntaxNode newType, CancellationToken cancellationToken) { var oldRoot = await _document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var newDocument = _document.WithSyntaxRoot( - oldRoot.ReplaceNode(oldType, newType)); - newDocument = await ImportAdder.AddImportsFromSymbolAnnotationAsync( - newDocument, - cancellationToken: cancellationToken).ConfigureAwait(false); + var newDocument = _document.WithSyntaxRoot(oldRoot.ReplaceNode(oldType, newType)); + var addImportOptions = await AddImportPlacementOptions.FromDocumentAsync(_document, cancellationToken).ConfigureAwait(false); + + newDocument = await ImportAdder.AddImportsFromSymbolAnnotationAsync(newDocument, addImportOptions, cancellationToken).ConfigureAwait(false); return newDocument; } diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs index be4f19821c438..76156efe808b6 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs @@ -119,7 +119,7 @@ private async Task HandleNonSelectionAsync(CodeRefactoringContext context) document, typeDeclaration, containingType, viableMembers, hasEquals, hasGetHashCode, withDialog: true, cancellationToken).ConfigureAwait(false); - context.RegisterRefactorings(actions); + context.RegisterRefactorings(actions, textSpan); } private static bool HasOperators(INamedTypeSymbol containingType) diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs index 7c97ed40b74a6..379432fe3f46f 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs @@ -598,9 +598,7 @@ public async Task GetChangedDocumentAsync( document.Project.Solution, TypeToGenerateIn, members.Concat(constructor), - new CodeGenerationOptions( - Token.GetLocation(), - options: await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false)), + new CodeGenerationContext(Token.GetLocation()), cancellationToken).ConfigureAwait(false); } @@ -654,9 +652,7 @@ private async Task GenerateMemberDelegatingConstructorAsync( preferThrowExpression: false, generateProperties: withProperties, IsContainedInUnsafeType), - new CodeGenerationOptions( - Token.GetLocation(), - options: await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false)), + new CodeGenerationContext(Token.GetLocation()), cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs index 42c8153cad85a..4e3ccd73d7e22 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs @@ -49,7 +49,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke name: _state.IdentifierToken.ValueText, hasConstantValue: value != null, constantValue: value), - new CodeGenerationOptions(contextLocation: _state.IdentifierToken.GetLocation()), + new CodeGenerationContext(contextLocation: _state.IdentifierToken.GetLocation()), cancellationToken) .ConfigureAwait(false); diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs index 964e4e63d9ae8..ac2cc6d29a833 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs @@ -64,7 +64,6 @@ private string GetDisplayText( protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) { - var syntaxTree = await _document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var syntaxFactory = _document.Project.Solution.Workspace.Services.GetLanguageServices(_state.TypeToGenerateIn.Language).GetService(); if (_generateProperty) @@ -75,7 +74,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke _document.Project.Solution, _state.TypeToGenerateIn, property, - new CodeGenerationOptions( + new CodeGenerationContext( afterThisLocation: _state.IdentifierToken.GetLocation(), generateMethodBodies: _state.TypeToGenerateIn.TypeKind != TypeKind.Interface), cancellationToken) @@ -91,10 +90,9 @@ protected override async Task GetChangedDocumentAsync(CancellationToke _document.Project.Solution, _state.TypeToGenerateIn, method, - new CodeGenerationOptions( + new CodeGenerationContext( afterThisLocation: _state.Location, - generateMethodBodies: _state.TypeToGenerateIn.TypeKind != TypeKind.Interface, - parseOptions: syntaxTree.Options), + generateMethodBodies: _state.TypeToGenerateIn.TypeKind != TypeKind.Interface), cancellationToken) .ConfigureAwait(false); diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs index f48f240ceb715..41bd598a11b5f 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs @@ -52,11 +52,10 @@ protected override async Task GetChangedDocumentAsync(CancellationToke var generateUnsafe = _state.TypeMemberType.RequiresUnsafeModifier() && !_state.IsContainedInUnsafeType; - var options = new CodeGenerationOptions( + var context = new CodeGenerationContext( afterThisLocation: _state.AfterThisLocation, beforeThisLocation: _state.BeforeThisLocation, - contextLocation: _state.IdentifierToken.GetLocation(), - options: await _semanticDocument.Document.GetOptionsAsync(cancellationToken).ConfigureAwait(false)); + contextLocation: _state.IdentifierToken.GetLocation()); if (_generateProperty) { @@ -79,7 +78,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke setMethod: setAccessor); return await CodeGenerator.AddPropertyDeclarationAsync( - solution, _state.TypeToGenerateIn, propertySymbol, options, cancellationToken).ConfigureAwait(false); + solution, _state.TypeToGenerateIn, propertySymbol, context, cancellationToken).ConfigureAwait(false); } else { @@ -93,7 +92,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke name: _state.IdentifierToken.ValueText); return await CodeGenerator.AddFieldDeclarationAsync( - solution, _state.TypeToGenerateIn, fieldSymbol, options, cancellationToken).ConfigureAwait(false); + solution, _state.TypeToGenerateIn, fieldSymbol, context, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs index 27a42fd4da25c..b6ebbe03a1fed 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs @@ -54,9 +54,9 @@ protected override async Task GetChangedDocumentAsync(CancellationToke private async Task GetNewRootAsync(CancellationToken cancellationToken) { var semanticModel = await _document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var documentOptions = await _document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var preferences = await CodeGenerationPreferences.FromDocumentAsync(_document, cancellationToken).ConfigureAwait(false); - if (_service.TryConvertToLocalDeclaration(_state.LocalType, _state.IdentifierToken, documentOptions, semanticModel, cancellationToken, out var newRoot)) + if (_service.TryConvertToLocalDeclaration(_state.LocalType, _state.IdentifierToken, semanticModel, cancellationToken, out var newRoot)) { return newRoot; } @@ -73,10 +73,13 @@ private async Task GetNewRootAsync(CancellationToken cancellationTok var codeGenService = _document.GetLanguageService(); var root = _state.IdentifierToken.GetAncestors().Last(); + var options = preferences.GetOptions( + new CodeGenerationContext(beforeThisLocation: _state.IdentifierToken.GetLocation())); + return codeGenService.AddStatements( root, SpecializedCollections.SingletonEnumerable(localStatement), - options: new CodeGenerationOptions(beforeThisLocation: _state.IdentifierToken.GetLocation()), + options, cancellationToken: cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs index fc388f67fc340..e3d9320f51a86 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddParameter; using Microsoft.CodeAnalysis.CodeActions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateVariable { @@ -40,9 +39,9 @@ public override string Title } } - protected override Task GetChangedSolutionAsync(CancellationToken cancellationToken) + protected override Task GetChangedSolutionAsync(CancellationToken cancellationToken) { - return AddParameterService.Instance.AddParameterAsync( + return AddParameterService.AddParameterAsync( _document, _state.ContainingMethod, _state.LocalType, @@ -50,7 +49,7 @@ protected override Task GetChangedSolutionAsync(CancellationToken canc _state.IdentifierToken.ValueText, newParameterIndex: null, _includeOverridesAndImplementations, - cancellationToken); + cancellationToken).AsNullable(); } } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs index 3b22a3fa641d7..17c3f07917cae 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs @@ -33,7 +33,7 @@ protected AbstractGenerateVariableService() protected abstract bool TryInitializeExplicitInterfaceState(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken, out SyntaxToken identifierToken, out IPropertySymbol propertySymbol, out INamedTypeSymbol typeToGenerateIn); protected abstract bool TryInitializeIdentifierNameState(SemanticDocument document, TSimpleNameSyntax identifierName, CancellationToken cancellationToken, out SyntaxToken identifierToken, out TExpressionSyntax simpleNameOrMemberAccessExpression, out bool isInExecutableBlock, out bool isinConditionalAccessExpression); - protected abstract bool TryConvertToLocalDeclaration(ITypeSymbol type, SyntaxToken identifierToken, OptionSet options, SemanticModel semanticModel, CancellationToken cancellationToken, out SyntaxNode newRoot); + protected abstract bool TryConvertToLocalDeclaration(ITypeSymbol type, SyntaxToken identifierToken, SemanticModel semanticModel, CancellationToken cancellationToken, out SyntaxNode newRoot); public async Task> GenerateVariableAsync( Document document, @@ -179,7 +179,7 @@ private static void AddParameterCodeActions(ArrayBuilder result, Doc { result.Add(new GenerateParameterCodeAction(document, state, includeOverridesAndImplementations: false)); - if (AddParameterService.Instance.HasCascadingDeclarations(state.ContainingMethod)) + if (AddParameterService.HasCascadingDeclarations(state.ContainingMethod)) result.Add(new GenerateParameterCodeAction(document, state, includeOverridesAndImplementations: true)); } } diff --git a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs index 99ab655fd829c..101eec10fb902 100644 --- a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs @@ -76,10 +76,9 @@ protected override async Task> ComputeOperation _document.Project.Solution, _containingType, members, - new CodeGenerationOptions( + new CodeGenerationContext( afterThisLocation: afterThisLocation, - contextLocation: syntaxTree.GetLocation(_textSpan), - options: await _document.GetOptionsAsync(cancellationToken).ConfigureAwait(false)), + contextLocation: syntaxTree.GetLocation(_textSpan)), cancellationToken).ConfigureAwait(false); return new CodeActionOperation[] diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs index 3845df9ac7c9d..0a34d81af7323 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs @@ -294,7 +294,7 @@ private async Task> GetGenerateInNewFileOperati newSolution, enclosingNamespace, rootNamespaceOrType, - new CodeGenerationOptions(newSemanticModel.SyntaxTree.GetLocation(new TextSpan())), + new CodeGenerationContext(newSemanticModel.SyntaxTree.GetLocation(new TextSpan())), _cancellationToken).ConfigureAwait(false); // containers is determined to be @@ -387,9 +387,7 @@ private async Task> GetGenerateIntoContainingNa solution, enclosingNamespace, namedType, - new CodeGenerationOptions( - afterThisLocation: _semanticDocument.SyntaxTree.GetLocation(_state.SimpleName.Span), - options: await _semanticDocument.Document.GetOptionsAsync(_cancellationToken).ConfigureAwait(false)), + new CodeGenerationContext(afterThisLocation: _semanticDocument.SyntaxTree.GetLocation(_state.SimpleName.Span)), _cancellationToken).ConfigureAwait(false); return new CodeActionOperation[] { new ApplyChangesOperation(codeGenResult.Project.Solution) }; @@ -434,7 +432,7 @@ private async Task> GetGenerateIntoExistingDocu solution, enclosingNamespaceGeneratedTypeToAddAndLocation.Item1, enclosingNamespaceGeneratedTypeToAddAndLocation.Item2, - new CodeGenerationOptions(afterThisLocation: enclosingNamespaceGeneratedTypeToAddAndLocation.Item3), + new CodeGenerationContext(afterThisLocation: enclosingNamespaceGeneratedTypeToAddAndLocation.Item3), _cancellationToken).ConfigureAwait(false); var newRoot = await codeGenResult.GetSyntaxRootAsync(_cancellationToken).ConfigureAwait(false); var updatedSolution = solution.WithDocumentSyntaxRoot(generateTypeOptionsResult.ExistingDocument.Id, newRoot, PreservationMode.PreserveIdentity); @@ -548,7 +546,7 @@ private async Task> GetGenerateIntoTypeOperatio solution, _state.TypeToGenerateInOpt, namedType, - new CodeGenerationOptions(contextLocation: _state.SimpleName.GetLocation()), + new CodeGenerationContext(contextLocation: _state.SimpleName.GetLocation()), _cancellationToken) .ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/GoToBase/AbstractGoToBaseService.cs b/src/Features/Core/Portable/GoToBase/AbstractGoToBaseService.cs similarity index 83% rename from src/EditorFeatures/Core/GoToBase/AbstractGoToBaseService.cs rename to src/Features/Core/Portable/GoToBase/AbstractGoToBaseService.cs index 060fd12c467c9..e54e30b177fdb 100644 --- a/src/EditorFeatures/Core/GoToBase/AbstractGoToBaseService.cs +++ b/src/Features/Core/Portable/GoToBase/AbstractGoToBaseService.cs @@ -7,15 +7,14 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindUsages; -namespace Microsoft.CodeAnalysis.Editor.GoToBase +namespace Microsoft.CodeAnalysis.GoToBase { internal abstract partial class AbstractGoToBaseService : IGoToBaseService { - public async Task FindBasesAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) + public async Task FindBasesAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) { var symbolAndProjectOpt = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync( document, position, cancellationToken).ConfigureAwait(false); @@ -23,7 +22,7 @@ public async Task FindBasesAsync(Document document, int position, IFindUsagesCon if (symbolAndProjectOpt == null) { await context.ReportMessageAsync( - EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret, cancellationToken).ConfigureAwait(false); + FeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret, cancellationToken).ConfigureAwait(false); return; } @@ -33,7 +32,7 @@ await context.ReportMessageAsync( var bases = await FindBaseHelpers.FindBasesAsync(symbol, solution, cancellationToken).ConfigureAwait(false); await context.SetSearchTitleAsync( - string.Format(EditorFeaturesResources._0_bases, + string.Format(FeaturesResources._0_bases, FindUsagesHelpers.GetDisplayName(symbol)), cancellationToken).ConfigureAwait(false); @@ -65,7 +64,7 @@ await context.SetSearchTitleAsync( if (!found) { - await context.ReportMessageAsync(EditorFeaturesResources.The_symbol_has_no_base, cancellationToken).ConfigureAwait(false); + await context.ReportMessageAsync(FeaturesResources.The_symbol_has_no_base, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/EditorFeatures/Core/GoToBase/FindBaseHelpers.cs b/src/Features/Core/Portable/GoToBase/FindBaseHelpers.cs similarity index 96% rename from src/EditorFeatures/Core/GoToBase/FindBaseHelpers.cs rename to src/Features/Core/Portable/GoToBase/FindBaseHelpers.cs index 472dbe07eabcd..6683edc969d74 100644 --- a/src/EditorFeatures/Core/GoToBase/FindBaseHelpers.cs +++ b/src/Features/Core/Portable/GoToBase/FindBaseHelpers.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.FindSymbols.FindReferences; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.GoToBase +namespace Microsoft.CodeAnalysis.GoToBase { internal static class FindBaseHelpers { diff --git a/src/EditorFeatures/Core/GoToBase/IGoToBaseService.cs b/src/Features/Core/Portable/GoToBase/IGoToBaseService.cs similarity index 78% rename from src/EditorFeatures/Core/GoToBase/IGoToBaseService.cs rename to src/Features/Core/Portable/GoToBase/IGoToBaseService.cs index ec7acee0f8a91..3572fea7b3ae7 100644 --- a/src/EditorFeatures/Core/GoToBase/IGoToBaseService.cs +++ b/src/Features/Core/Portable/GoToBase/IGoToBaseService.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.CodeAnalysis.Editor.GoToBase +namespace Microsoft.CodeAnalysis.GoToBase { internal interface IGoToBaseService : ILanguageService { @@ -15,6 +15,6 @@ internal interface IGoToBaseService : ILanguageService /// Finds the base members overridden or implemented by the symbol at the specific position in the document, /// pushing the results into the context instance. /// - Task FindBasesAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken); + Task FindBasesAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/GoToDefinition/AbstractFindDefinitionService.cs b/src/Features/Core/Portable/GoToDefinition/AbstractFindDefinitionService.cs index 6764b41ce3263..88c55975f02f1 100644 --- a/src/Features/Core/Portable/GoToDefinition/AbstractFindDefinitionService.cs +++ b/src/Features/Core/Portable/GoToDefinition/AbstractFindDefinitionService.cs @@ -5,8 +5,8 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/EditorFeatures/Core/Extensibility/Highlighting/ExportHighlighterAttribute.cs b/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs similarity index 89% rename from src/EditorFeatures/Core/Extensibility/Highlighting/ExportHighlighterAttribute.cs rename to src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs index fa2ef4989245d..cac89248f7914 100644 --- a/src/EditorFeatures/Core/Extensibility/Highlighting/ExportHighlighterAttribute.cs +++ b/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs @@ -5,10 +5,10 @@ #nullable disable using System; -using System.ComponentModel.Composition; +using System.Composition; using System.Diagnostics.CodeAnalysis; -namespace Microsoft.CodeAnalysis.Editor +namespace Microsoft.CodeAnalysis.Highlighting { [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] diff --git a/src/EditorFeatures/Core/Implementation/KeywordHighlighting/HighlightingService.cs b/src/Features/Core/Portable/Highlighting/HighlightingService.cs similarity index 96% rename from src/EditorFeatures/Core/Implementation/KeywordHighlighting/HighlightingService.cs rename to src/Features/Core/Portable/Highlighting/HighlightingService.cs index 4b980219b4e63..07e3611d98bea 100644 --- a/src/EditorFeatures/Core/Implementation/KeywordHighlighting/HighlightingService.cs +++ b/src/Features/Core/Portable/Highlighting/HighlightingService.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +namespace Microsoft.CodeAnalysis.Highlighting { [Export(typeof(IHighlightingService))] [Shared] diff --git a/src/EditorFeatures/Core/Extensibility/Highlighting/IHighlighter.cs b/src/Features/Core/Portable/Highlighting/IHighlighter.cs similarity index 91% rename from src/EditorFeatures/Core/Extensibility/Highlighting/IHighlighter.cs rename to src/Features/Core/Portable/Highlighting/IHighlighter.cs index 9649f7bdd8ac3..8d1da15886592 100644 --- a/src/EditorFeatures/Core/Extensibility/Highlighting/IHighlighter.cs +++ b/src/Features/Core/Portable/Highlighting/IHighlighter.cs @@ -8,7 +8,7 @@ using System.Threading; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor +namespace Microsoft.CodeAnalysis.Highlighting { internal interface IHighlighter { diff --git a/src/EditorFeatures/Core/IHighlightingService.cs b/src/Features/Core/Portable/Highlighting/IHighlightingService.cs similarity index 94% rename from src/EditorFeatures/Core/IHighlightingService.cs rename to src/Features/Core/Portable/Highlighting/IHighlightingService.cs index 2322db06348b7..6aab5033d8d37 100644 --- a/src/EditorFeatures/Core/IHighlightingService.cs +++ b/src/Features/Core/Portable/Highlighting/IHighlightingService.cs @@ -8,7 +8,7 @@ using System.Threading; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor +namespace Microsoft.CodeAnalysis.Highlighting { internal interface IHighlightingService { diff --git a/src/EditorFeatures/Core/Implementation/KeywordHighlighting/AbstractKeywordHighlighter.cs b/src/Features/Core/Portable/Highlighting/Keywords/AbstractKeywordHighlighter.cs similarity index 98% rename from src/EditorFeatures/Core/Implementation/KeywordHighlighting/AbstractKeywordHighlighter.cs rename to src/Features/Core/Portable/Highlighting/Keywords/AbstractKeywordHighlighter.cs index 78822c072ff00..aa1183be975bb 100644 --- a/src/EditorFeatures/Core/Implementation/KeywordHighlighting/AbstractKeywordHighlighter.cs +++ b/src/Features/Core/Portable/Highlighting/Keywords/AbstractKeywordHighlighter.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +namespace Microsoft.CodeAnalysis.Highlighting { internal abstract class AbstractKeywordHighlighter : AbstractKeywordHighlighter where TNode : SyntaxNode { diff --git a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs b/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs index fd78fc5a477c8..b6f3e094d41e3 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs +++ b/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs @@ -105,16 +105,19 @@ public async Task ImplementAbstractClassAsync( FeaturesResources.Base_classes_contain_inaccessible_unimplemented_members))); } - var options = await _document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var updatedClassNode = CodeGenerator.AddMemberDeclarations( + var context = new CodeGenerationContext( + contextLocation: classNodeToAddMembersTo.GetLocation(), + autoInsertionLocation: groupMembers, + sortMembers: groupMembers); + + var codeGenerator = _document.GetRequiredLanguageService(); + var options = await CodeGenerationOptions.FromDocumentAsync(context, _document, cancellationToken).ConfigureAwait(false); + + var updatedClassNode = codeGenerator.AddMembers( classNodeToAddMembersTo, memberDefinitions, - _document.Project.Solution.Workspace, - new CodeGenerationOptions( - contextLocation: classNodeToAddMembersTo.GetLocation(), - autoInsertionLocation: groupMembers, - sortMembers: groupMembers, - options: options)); + options, + cancellationToken); var root = await _document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newRoot = root.ReplaceNode(_classNode, updatedClassNode); diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs index 8b1dce2749de2..359183f3815c6 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs +++ b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs @@ -208,13 +208,13 @@ protected async Task GetUpdatedDocumentAsync( Options.InsertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind; return await CodeGenerator.AddMemberDeclarationsAsync( - result.Project.Solution, classOrStructType, + result.Project.Solution, + classOrStructType, memberDefinitions.Concat(extraMembers), - new CodeGenerationOptions( + new CodeGenerationContext( contextLocation: classOrStructDecl.GetLocation(), autoInsertionLocation: groupMembers, - sortMembers: groupMembers, - options: await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false)), + sortMembers: groupMembers), cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs index ccc4517226375..860c90e995a1b 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs +++ b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs @@ -151,15 +151,20 @@ public override async Task GetUpdatedDocumentAsync( var firstGeneratedMember = rootWithCoreMembers.GetAnnotatedNodes(CodeGenerator.Annotation).First(); var typeDeclarationWithCoreMembers = firstGeneratedMember.Parent!; - var typeDeclarationWithAllMembers = CodeGenerator.AddMemberDeclarations( + var codeGenerator = document.GetRequiredLanguageService(); + + var context = new CodeGenerationContext( + addImports: false, + sortMembers: false, + autoInsertionLocation: false); + + var codeGenerationOptions = await CodeGenerationOptions.FromDocumentAsync(context, document, cancellationToken).ConfigureAwait(false); + + var typeDeclarationWithAllMembers = codeGenerator.AddMembers( typeDeclarationWithCoreMembers, disposableMethods, - document.Project.Solution.Workspace, - new CodeGenerationOptions( - addImports: false, - parseOptions: rootWithCoreMembers.SyntaxTree.Options, - sortMembers: false, - autoInsertionLocation: false)); + codeGenerationOptions, + cancellationToken); var docWithAllMembers = docWithCoreMembers.WithSyntaxRoot( rootWithCoreMembers.ReplaceNode( @@ -291,12 +296,16 @@ private IMethodSymbol CreateDisposeInterfaceMethod( g.Argument(DisposingName, RefKind.None, g.TrueLiteralExpression()))))); // GC.SuppressFinalize(this); - statements.Add(g.ExpressionStatement( - g.InvocationExpression( - g.MemberAccessExpression( - g.TypeExpression(compilation.GetTypeByMetadataName(typeof(GC).FullName!)), - nameof(GC.SuppressFinalize)), - g.ThisExpression()))); + var gcType = compilation.GetTypeByMetadataName(typeof(GC).FullName!); + if (gcType != null) + { + statements.Add(g.ExpressionStatement( + g.InvocationExpression( + g.MemberAccessExpression( + g.TypeExpression(gcType), + nameof(GC.SuppressFinalize)), + g.ThisExpression()))); + } var modifiers = DeclarationModifiers.From(disposeMethod); modifiers = modifiers.WithIsAbstract(false); diff --git a/src/Features/Core/Portable/IncrementalCaches/SyntaxTreeInfoIncrementalAnalyzerProvider.cs b/src/Features/Core/Portable/IncrementalCaches/SyntaxTreeInfoIncrementalAnalyzerProvider.cs index 89d1d019c7fcf..285fc09e1f2a7 100644 --- a/src/Features/Core/Portable/IncrementalCaches/SyntaxTreeInfoIncrementalAnalyzerProvider.cs +++ b/src/Features/Core/Portable/IncrementalCaches/SyntaxTreeInfoIncrementalAnalyzerProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using System.Threading; @@ -28,15 +26,16 @@ public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) private class IncrementalAnalyzer : IncrementalAnalyzerBase { - public override Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken) + 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 Task.CompletedTask; + return; } - return SyntaxTreeIndex.PrecalculateAsync(document, cancellationToken); + await SyntaxTreeIndex.PrecalculateAsync(document, cancellationToken).ConfigureAwait(false); + await TopLevelSyntaxTreeIndex.PrecalculateAsync(document, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/EditorFeatures/Core/InheritanceMargin/InheritanceMarginServiceHelpers.cs b/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginServiceHelpers.cs similarity index 87% rename from src/EditorFeatures/Core/InheritanceMargin/InheritanceMarginServiceHelpers.cs rename to src/Features/Core/Portable/InheritanceMargin/InheritanceMarginServiceHelpers.cs index 875b49ff4f9bb..499d0d7f2c881 100644 --- a/src/EditorFeatures/Core/InheritanceMargin/InheritanceMarginServiceHelpers.cs +++ b/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginServiceHelpers.cs @@ -7,13 +7,13 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindSymbols.FindReferences; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.InheritanceMargin { @@ -219,6 +219,7 @@ private static async ValueTask CreateInherita { var baseSymbolItems = await baseSymbols .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -229,6 +230,7 @@ private static async ValueTask CreateInherita var derivedTypeItems = await derivedTypesSymbols .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync(solution, symbol, @@ -252,6 +254,7 @@ private static async ValueTask CreateInherita { var implementedMemberItems = await implementingMembers .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -278,6 +281,7 @@ private static async ValueTask CreateInherita // and if it is an class/struct, it whould be shown as 'Base Type' var baseSymbolItems = await baseSymbols .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -287,6 +291,7 @@ private static async ValueTask CreateInherita var derivedTypeItems = await derivedTypesSymbols .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync(solution, symbol, @@ -312,6 +317,7 @@ private static async ValueTask CreateInherita { var implementedMemberItems = await implementedMembers .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -321,6 +327,7 @@ private static async ValueTask CreateInherita var overridenMemberItems = await overriddenMembers .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -330,6 +337,7 @@ private static async ValueTask CreateInherita var overridingMemberItems = await overridingMembers .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -354,9 +362,9 @@ private static async ValueTask CreateInherita targetSymbol = symbolInSource ?? targetSymbol; // Right now the targets are not shown in a classified way. - var definition = await targetSymbol.ToNonClassifiedDefinitionItemAsync( + var definition = await ToSlimDefinitionItemAsync( + targetSymbol, solution, - includeHiddenLocations: false, cancellationToken: cancellationToken).ConfigureAwait(false); var displayName = targetSymbol.ToDisplayString(s_displayFormat); @@ -487,5 +495,66 @@ private static async Task> GetDerivedTypesAndIm cancellationToken: cancellationToken).ConfigureAwait(false); } } + + /// + /// Create the DefinitionItem based on the numbers of locations for . + /// If there is only one location, create the DefinitionItem contains only the documentSpan or symbolKey to save memory. + /// Because in such case, when clicking InheritanceMarginGlpph, it will directly navigate to the symbol. + /// Otherwise, create the full non-classified DefinitionItem. Because in such case we want to display all the locations to the user + /// by reusing the FAR window. + /// + private static async Task ToSlimDefinitionItemAsync(ISymbol symbol, Solution solution, CancellationToken cancellationToken) + { + RoslynDebug.Assert(IsNavigableSymbol(symbol)); + var locations = symbol.Locations; + if (locations.Length > 1) + { + return await symbol.ToNonClassifiedDefinitionItemAsync( + solution, + includeHiddenLocations: false, + cancellationToken: cancellationToken).ConfigureAwait(false); + } + + if (locations.Length == 1) + { + var location = locations[0]; + if (location.IsInMetadata) + { + return DefinitionItem.CreateMetadataDefinition( + tags: ImmutableArray.Empty, + displayParts: ImmutableArray.Empty, + nameDisplayParts: ImmutableArray.Empty, + solution, + symbol); + } + else if (location.IsInSource && location.IsVisibleSourceLocation()) + { + var document = solution.GetDocument(location.SourceTree); + if (document != null) + { + var documentSpan = new DocumentSpan(document, location.SourceSpan); + return DefinitionItem.Create( + tags: ImmutableArray.Empty, + displayParts: ImmutableArray.Empty, + documentSpan, + nameDisplayParts: ImmutableArray.Empty); + } + } + } + + throw ExceptionUtilities.Unreachable; + } + + private static bool IsNavigableSymbol(ISymbol symbol) + { + var locations = symbol.Locations; + if (locations.Length == 1) + { + var location = locations[0]; + return location.IsInMetadata || (location.IsInSource && location.IsVisibleSourceLocation()); + } + + return !locations.IsEmpty; + } } } diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs index 21c83ad5ae0dd..62c1143f6fcda 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -37,13 +38,6 @@ internal abstract partial class AbstractAddParameterCheckCodeRefactoringProvider where TExpressionSyntax : SyntaxNode where TBinaryExpressionSyntax : TExpressionSyntax { - private readonly Func _isFunctionDeclarationFunc; - - protected AbstractAddParameterCheckCodeRefactoringProvider() - { - _isFunctionDeclarationFunc = IsFunctionDeclaration; - } - protected abstract bool CanOffer(SyntaxNode body); protected abstract bool PrefersThrowExpression(DocumentOptionSet options); protected abstract string EscapeResourceString(string input); @@ -51,8 +45,13 @@ protected AbstractAddParameterCheckCodeRefactoringProvider() protected abstract Document? TryAddNullCheckToParameterDeclaration(Document document, TParameterSyntax parameterSyntax, CancellationToken cancellationToken); protected override async Task> GetRefactoringsForAllParametersAsync( - Document document, SyntaxNode functionDeclaration, IMethodSymbol methodSymbol, - IBlockOperation? blockStatementOpt, ImmutableArray listOfParameterNodes, TextSpan parameterSpan, CancellationToken cancellationToken) + Document document, + SyntaxNode funcOrRecord, + IMethodSymbol methodSymbol, + IBlockOperation? blockStatementOpt, + ImmutableArray listOfParameterNodes, + TextSpan parameterSpan, + CancellationToken cancellationToken) { // List to keep track of the valid parameters var listOfParametersOrdinals = new List(); @@ -62,16 +61,12 @@ protected override async Task> GetRefactoringsForAllP { var parameter = (IParameterSymbol)semanticModel.GetRequiredDeclaredSymbol(parameterNode, cancellationToken); if (ParameterValidForNullCheck(document, parameter, semanticModel, blockStatementOpt, cancellationToken)) - { listOfParametersOrdinals.Add(parameter.Ordinal); - } } // Min 2 parameters to offer the refactoring if (listOfParametersOrdinals.Count < 2) - { return ImmutableArray.Empty; - } // Great. The list has parameters that need null checks. Offer to add null checks for all. return ImmutableArray.Create(new MyCodeAction( @@ -84,7 +79,7 @@ protected override async Task> GetRefactoringsForSing Document document, TParameterSyntax parameterSyntax, IParameterSymbol parameter, - SyntaxNode functionDeclaration, + SyntaxNode funcOrRecord, IMethodSymbol methodSymbol, IBlockOperation? blockStatementOpt, CancellationToken cancellationToken) @@ -93,33 +88,32 @@ protected override async Task> GetRefactoringsForSing // Only should provide null-checks for reference types and nullable types. if (!ParameterValidForNullCheck(document, parameter, semanticModel, blockStatementOpt, cancellationToken)) - { return ImmutableArray.Empty; - } // Great. There was no null check. Offer to add one. - using var _ = ArrayBuilder.GetInstance(out var result); + using var result = TemporaryArray.Empty; result.Add(new MyCodeAction( FeaturesResources.Add_null_check, - c => AddNullCheckAsync(document, parameterSyntax, parameter, functionDeclaration, methodSymbol, blockStatementOpt, c), + c => AddNullCheckAsync(document, parameterSyntax, parameter, funcOrRecord, methodSymbol, blockStatementOpt, c), nameof(FeaturesResources.Add_null_check))); - // Also, if this was a string, offer to add the special checks to - // string.IsNullOrEmpty and string.IsNullOrWhitespace. - if (parameter.Type.SpecialType == SpecialType.System_String) + // Also, if this was a string, offer to add the special checks to string.IsNullOrEmpty and + // string.IsNullOrWhitespace. We cannot do this for records though as they have no location + // to place the checks. + if (parameter.Type.SpecialType == SpecialType.System_String && !IsRecordDeclaration(funcOrRecord)) { result.Add(new MyCodeAction( FeaturesResources.Add_string_IsNullOrEmpty_check, - c => AddStringCheckAsync(document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, nameof(string.IsNullOrEmpty), c), + c => AddStringCheckAsync(document, parameter, funcOrRecord, methodSymbol, blockStatementOpt, nameof(string.IsNullOrEmpty), c), nameof(FeaturesResources.Add_string_IsNullOrEmpty_check))); result.Add(new MyCodeAction( FeaturesResources.Add_string_IsNullOrWhiteSpace_check, - c => AddStringCheckAsync(document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, nameof(string.IsNullOrWhiteSpace), c), + c => AddStringCheckAsync(document, parameter, funcOrRecord, methodSymbol, blockStatementOpt, nameof(string.IsNullOrWhiteSpace), c), nameof(FeaturesResources.Add_string_IsNullOrWhiteSpace_check))); } - return result.ToImmutable(); + return result.ToImmutableAndClear(); } private async Task UpdateDocumentForRefactoringAsync( @@ -135,12 +129,13 @@ private async Task UpdateDocumentForRefactoringAsync( var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var firstParameterNode = (TParameterSyntax)root.FindNode(parameterSpan); - var functionDeclaration = firstParameterNode.FirstAncestorOrSelf(_isFunctionDeclarationFunc); - if (functionDeclaration == null) + var funcOrRecord = firstParameterNode.FirstAncestorOrSelf(_isFunctionDeclarationFunc) ?? + firstParameterNode.FirstAncestorOrSelf(_isRecordDeclarationFunc); + if (funcOrRecord == null) continue; var generator = SyntaxGenerator.GetGenerator(document); - var parameterNodes = (IReadOnlyList)generator.GetParameters(functionDeclaration); + var parameterNodes = (IReadOnlyList)generator.GetParameters(funcOrRecord); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var (parameterSyntax, parameter) = GetParameterAtOrdinal(index, parameterNodes, semanticModel, cancellationToken); if (parameter == null) @@ -149,20 +144,19 @@ private async Task UpdateDocumentForRefactoringAsync( var syntaxFacts = document.GetRequiredLanguageService(); - if (!CanOfferRefactoring(functionDeclaration, semanticModel, syntaxFacts, cancellationToken, out blockStatementOpt)) - { + if (!CanOfferRefactoring(funcOrRecord, semanticModel, syntaxFacts, cancellationToken, out blockStatementOpt)) continue; - } - // If parameter is a string, default check would be IsNullOrEmpty. This is because IsNullOrEmpty is more commonly used in this regard according to telemetry and UX testing. - if (parameter.Type.SpecialType == SpecialType.System_String) + // If parameter is a string, default check would be IsNullOrEmpty. This is because IsNullOrEmpty is more + // commonly used in this regard according to telemetry and UX testing. + if (parameter.Type.SpecialType == SpecialType.System_String && !IsRecordDeclaration(funcOrRecord)) { - document = await AddStringCheckAsync(document, parameter, functionDeclaration, (IMethodSymbol)parameter.ContainingSymbol, blockStatementOpt, nameof(string.IsNullOrEmpty), cancellationToken).ConfigureAwait(false); + document = await AddStringCheckAsync(document, parameter, funcOrRecord, (IMethodSymbol)parameter.ContainingSymbol, blockStatementOpt, nameof(string.IsNullOrEmpty), cancellationToken).ConfigureAwait(false); continue; } // For all other parameters, add null check - updates document - document = await AddNullCheckAsync(document, parameterSyntax, parameter, functionDeclaration, + document = await AddNullCheckAsync(document, parameterSyntax, parameter, funcOrRecord, (IMethodSymbol)parameter.ContainingSymbol, blockStatementOpt, cancellationToken).ConfigureAwait(false); } @@ -264,7 +258,12 @@ protected bool ParameterValidForNullCheck(Document document, IParameterSymbol pa return false; } - if (parameter.IsNullChecked) + if (parameter.IsDiscard) + { + return false; + } + + if (document.GetRequiredLanguageService().IsNullChecked(parameter, cancellationToken)) { return false; } @@ -383,7 +382,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); + var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.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 87079e49d8f8e..877209aba34b9 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs @@ -40,11 +40,12 @@ internal abstract partial class AbstractInitializeMemberFromParameterCodeRefacto where TExpressionSyntax : SyntaxNode { protected abstract SyntaxNode? TryGetLastStatement(IBlockOperation? blockStatementOpt); - protected abstract Accessibility DetermineDefaultFieldAccessibility(INamedTypeSymbol containingType); - protected abstract Accessibility DetermineDefaultPropertyAccessibility(); + protected override bool SupportsRecords(ParseOptions options) + => false; + protected override Task> GetRefactoringsForAllParametersAsync( Document document, SyntaxNode functionDeclaration, IMethodSymbol method, IBlockOperation? blockStatementOpt, ImmutableArray listOfParameterNodes, TextSpan parameterSpan, CancellationToken cancellationToken) @@ -422,11 +423,12 @@ private async Task AddSingleSymbolInitializationAsync( ISymbol fieldOrProperty, CancellationToken cancellationToken) { - var workspace = document.Project.Solution.Workspace; + var services = document.Project.Solution.Workspace.Services; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, workspace); + var editor = new SyntaxEditor(root, services); var generator = editor.Generator; - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var preferences = await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var codeGenerator = document.GetRequiredLanguageService(); if (fieldOrProperty.ContainingType == null) { @@ -450,15 +452,17 @@ private async Task AddSingleSymbolInitializationAsync( { if (fieldOrProperty is IPropertySymbol property) { - return CodeGenerator.AddPropertyDeclaration( - currentTypeDecl, property, workspace, - GetAddOptions(parameter, blockStatementOpt, typeDeclaration, options, cancellationToken)); + return codeGenerator.AddProperty( + currentTypeDecl, property, + preferences.GetOptions(GetAddContext(parameter, blockStatementOpt, typeDeclaration, cancellationToken)), + cancellationToken); } else if (fieldOrProperty is IFieldSymbol field) { - return CodeGenerator.AddFieldDeclaration( - currentTypeDecl, field, workspace, - GetAddOptions(parameter, blockStatementOpt, typeDeclaration, options, cancellationToken)); + return codeGenerator.AddField( + currentTypeDecl, field, + preferences.GetOptions(GetAddContext(parameter, blockStatementOpt, typeDeclaration, cancellationToken)), + cancellationToken); } else { @@ -486,15 +490,15 @@ private async Task AddSingleSymbolInitializationAsync( return document.WithSyntaxRoot(editor.GetChangedRoot()); } - private static CodeGenerationOptions GetAddOptions( - IParameterSymbol parameter, IBlockOperation? blockStatementOpt, - SyntaxNode typeDeclaration, OptionSet options, CancellationToken cancellationToken) + private static CodeGenerationContext GetAddContext( + IParameterSymbol parameter, IBlockOperation? blockStatement, + SyntaxNode typeDeclaration, CancellationToken cancellationToken) where TSymbol : ISymbol { foreach (var (sibling, before) in GetSiblingParameters(parameter)) { var statement = TryFindFieldOrPropertyAssignmentStatement( - sibling, blockStatementOpt, out var fieldOrProperty); + sibling, blockStatement, out var fieldOrProperty); if (statement != null && fieldOrProperty is TSymbol symbol) @@ -506,19 +510,19 @@ private static CodeGenerationOptions GetAddOptions( { // Found an existing field/property that corresponds to a preceding parameter. // Place ourselves directly after it. - return new CodeGenerationOptions(afterThisLocation: symbolSyntax.GetLocation(), options: options); + return new CodeGenerationContext(afterThisLocation: symbolSyntax.GetLocation()); } else { // Found an existing field/property that corresponds to a following parameter. // Place ourselves directly before it. - return new CodeGenerationOptions(beforeThisLocation: symbolSyntax.GetLocation(), options: options); + return new CodeGenerationContext(beforeThisLocation: symbolSyntax.GetLocation()); } } } } - return new CodeGenerationOptions(options: options); + return CodeGenerationContext.Default; } private static ImmutableArray<(IParameterSymbol parameter, bool before)> GetSiblingParameters(IParameterSymbol parameter) diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs index 9046a16c44144..afb66666f0c42 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs @@ -29,18 +29,27 @@ internal abstract partial class AbstractInitializeParameterCodeRefactoringProvid where TStatementSyntax : SyntaxNode where TExpressionSyntax : SyntaxNode { - private readonly Func _isFunctionDeclarationFunc; + protected readonly Func _isFunctionDeclarationFunc; + protected readonly Func _isRecordDeclarationFunc; protected AbstractInitializeParameterCodeRefactoringProvider() { _isFunctionDeclarationFunc = IsFunctionDeclaration; + _isRecordDeclarationFunc = IsRecordDeclaration; } + protected abstract ISyntaxFacts SyntaxFacts { get; } + + protected abstract bool SupportsRecords(ParseOptions options); protected abstract bool IsFunctionDeclaration(SyntaxNode node); protected abstract bool IsImplicitConversion(Compilation compilation, ITypeSymbol source, ITypeSymbol destination); protected abstract SyntaxNode GetBody(SyntaxNode functionDeclaration); + protected bool IsRecordDeclaration(SyntaxNode node) + => this.SyntaxFacts.SyntaxKinds.RecordDeclaration == node.RawKind || + this.SyntaxFacts.SyntaxKinds.RecordStructDeclaration == node.RawKind; + protected abstract Task> GetRefactoringsForAllParametersAsync( Document document, SyntaxNode functionDeclaration, @@ -72,27 +81,26 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var selectedParameter = await context.TryGetRelevantNodeAsync().ConfigureAwait(false); if (selectedParameter == null) - { return; - } - var functionDeclaration = selectedParameter.FirstAncestorOrSelf(_isFunctionDeclarationFunc); - if (functionDeclaration is null) - { + var funcOrRecord = + selectedParameter.FirstAncestorOrSelf(_isFunctionDeclarationFunc) ?? + selectedParameter.FirstAncestorOrSelf(_isRecordDeclarationFunc); + if (funcOrRecord is null) + return; + + if (IsRecordDeclaration(funcOrRecord) && !this.SupportsRecords(funcOrRecord.SyntaxTree.Options)) return; - } var generator = SyntaxGenerator.GetGenerator(document); - var parameterNodes = generator.GetParameters(functionDeclaration); + var parameterNodes = generator.GetParameters(funcOrRecord); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService(); // we can't just call GetDeclaredSymbol on functionDeclaration because it could an anonymous function, // so first we have to get the parameter symbol and then its containing method symbol if (!TryGetParameterSymbol(selectedParameter, semanticModel, out var parameter, cancellationToken)) - { return; - } var methodSymbol = (IMethodSymbol)parameter.ContainingSymbol; if (methodSymbol.IsAbstract || @@ -107,16 +115,14 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // as we use it later on in our computations. var argumentNullExceptionType = typeof(ArgumentNullException).FullName; if (argumentNullExceptionType is null || semanticModel.Compilation.GetTypeByMetadataName(argumentNullExceptionType) is null) - { return; - } - if (CanOfferRefactoring(functionDeclaration, semanticModel, syntaxFacts, cancellationToken, out var blockStatementOpt)) + if (CanOfferRefactoring(funcOrRecord, semanticModel, syntaxFacts, cancellationToken, out var blockStatementOpt)) { // Ok. Looks like the selected parameter could be refactored. Defer to subclass to // actually determine if there are any viable refactorings here. var refactorings = await GetRefactoringsForSingleParameterAsync( - document, selectedParameter, parameter, functionDeclaration, methodSymbol, blockStatementOpt, cancellationToken).ConfigureAwait(false); + document, selectedParameter, parameter, funcOrRecord, methodSymbol, blockStatementOpt, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(refactorings, context.Span); } @@ -136,7 +142,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // Looks like we can offer a refactoring for more than one parameter. Defer to subclass to // actually determine if there are any viable refactorings here. var refactorings = await GetRefactoringsForAllParametersAsync( - document, functionDeclaration, methodSymbol, blockStatementOpt, + document, funcOrRecord, methodSymbol, blockStatementOpt, listOfPotentiallyValidParametersNodes.ToImmutable(), selectedParameter.Span, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(refactorings, context.Span); } @@ -156,12 +162,15 @@ static bool TryGetParameterSymbol( } protected bool CanOfferRefactoring( - SyntaxNode functionDeclaration, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, + SyntaxNode funcOrRecord, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken, out IBlockOperation? blockStatementOpt) { blockStatementOpt = null; - var functionBody = GetBody(functionDeclaration); + if (IsRecordDeclaration(funcOrRecord)) + return true; + + var functionBody = GetBody(funcOrRecord); if (functionBody == null) { // We support initializing parameters, even when the containing member doesn't have a @@ -174,7 +183,7 @@ protected bool CanOfferRefactoring( // get it via `IAnonymousFunctionOperation.Body` instead of getting it directly from the body syntax. var operation = semanticModel.GetOperation( - syntaxFacts.IsAnonymousFunctionExpression(functionDeclaration) ? functionDeclaration : functionBody, + syntaxFacts.IsAnonymousFunctionExpression(funcOrRecord) ? funcOrRecord : functionBody, cancellationToken); if (operation == null) diff --git a/src/Features/Core/Portable/InlineTemporary/AbstractInlineTemporaryCodeRefactoringProvider.cs b/src/Features/Core/Portable/InlineTemporary/AbstractInlineTemporaryCodeRefactoringProvider.cs index 5d282fc9823f3..e703e7d9a5474 100644 --- a/src/Features/Core/Portable/InlineTemporary/AbstractInlineTemporaryCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InlineTemporary/AbstractInlineTemporaryCodeRefactoringProvider.cs @@ -32,7 +32,7 @@ protected static async Task> GetReferenceL // Do not cascade when finding references to this local. Cascading can cause us to find linked // references as well which can throw things off for us. For inline variable, we only care about the // direct real references in this project context. - var options = FindReferencesSearchOptions.Default.With(cascade: false); + var options = FindReferencesSearchOptions.Default with { Cascade = false }; var findReferencesResult = await SymbolFinder.FindReferencesAsync( local, document.Project.Solution, options, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs index d877104f3c395..b775d534cdbbb 100644 --- a/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs @@ -31,7 +31,7 @@ internal abstract class AbstractIntroduceUsingStatementCodeRefactoringProvider GetStatements(SyntaxNode parentOfStatementsToSurround); protected abstract SyntaxNode WithStatements(SyntaxNode parentOfStatementsToSurround, SyntaxList statements); - protected abstract TStatementSyntax CreateUsingStatement(TLocalDeclarationSyntax declarationStatement, SyntaxTriviaList sameLineTrivia, SyntaxList statementsToSurround); + protected abstract TStatementSyntax CreateUsingStatement(TLocalDeclarationSyntax declarationStatement, SyntaxList statementsToSurround); public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { @@ -123,20 +123,11 @@ private async Task IntroduceUsingStatementAsync( var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var syntaxFactsService = document.GetRequiredLanguageService(); + var syntaxFacts = document.GetRequiredLanguageService(); - var statementsToSurround = GetStatementsToSurround(declarationStatement, semanticModel, syntaxFactsService, cancellationToken); + var statementsToSurround = GetStatementsToSurround(declarationStatement, semanticModel, syntaxFacts, cancellationToken); - // Separate the newline from the trivia that is going on the using declaration line. - var (sameLine, endOfLine) = SplitTrailingTrivia(declarationStatement, syntaxFactsService); - - var usingStatement = - CreateUsingStatement( - declarationStatement, - sameLine, - statementsToSurround) - .WithLeadingTrivia(declarationStatement.GetLeadingTrivia()) - .WithTrailingTrivia(endOfLine); + var usingStatement = CreateUsingStatement(declarationStatement, statementsToSurround); if (statementsToSurround.Any()) { @@ -193,16 +184,6 @@ private SyntaxList GetStatementsToSurround( .Skip(declarationStatementIndex + 1)); } - private static (SyntaxTriviaList sameLine, SyntaxTriviaList endOfLine) SplitTrailingTrivia(SyntaxNode node, ISyntaxFactsService syntaxFactsService) - { - var trailingTrivia = node.GetTrailingTrivia(); - var lastIndex = trailingTrivia.Count - 1; - - return lastIndex != -1 && syntaxFactsService.IsEndOfLineTrivia(trailingTrivia[lastIndex]) - ? (sameLine: trailingTrivia.RemoveAt(lastIndex), endOfLine: new SyntaxTriviaList(trailingTrivia[lastIndex])) - : (sameLine: trailingTrivia, endOfLine: SyntaxTriviaList.Empty); - } - private static TStatementSyntax FindSiblingStatementContainingLastUsage( TStatementSyntax declarationSyntax, SemanticModel semanticModel, diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs index 53c8610ad3170..b3d4dd35fc439 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs @@ -449,12 +449,14 @@ private async Task CreateMethodDeclarationAsync(SyntaxNode newStatem string? newMethodIdentifier, ITypeSymbol? typeSymbol, bool isTrampoline, CancellationToken cancellationToken) { var codeGenerationService = _originalDocument.GetRequiredLanguageService(); - var options = await _originalDocument.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var codeGenOptions = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, _originalDocument, cancellationToken).ConfigureAwait(false); var newMethod = isTrampoline ? CodeGenerationSymbolFactory.CreateMethodSymbol(_methodSymbol, name: newMethodIdentifier, parameters: validParameters, statements: ImmutableArray.Create(newStatement), returnType: typeSymbol) : CodeGenerationSymbolFactory.CreateMethodSymbol(_methodSymbol, statements: ImmutableArray.Create(newStatement), containingType: _methodSymbol.ContainingType); - var newMethodDeclaration = codeGenerationService.CreateMethodDeclaration(newMethod, options: new CodeGenerationOptions(options: options, parseOptions: _expression.SyntaxTree.Options)); + + var newMethodDeclaration = codeGenerationService.CreateMethodDeclaration(newMethod, CodeGenerationDestination.Unspecified, codeGenOptions, cancellationToken); + Contract.ThrowIfNull(newMethodDeclaration); return newMethodDeclaration; } diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs index 581c51d514e80..f874b000e3696 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs @@ -97,6 +97,12 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex return; } + var expressionSymbol = semanticModel.GetSymbolInfo(expression, cancellationToken).Symbol; + if (expressionSymbol is IParameterSymbol parameterSymbol && parameterSymbol.ContainingSymbol.Equals(containingSymbol)) + { + return; + } + // Code actions for trampoline and overloads will not be offered if the method is a constructor. // Code actions for overloads will not be offered if the method if the method is a local function. var methodKind = methodSymbol.MethodKind; diff --git a/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs b/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs index 84a20c63a83ef..59da6609cc87e 100644 --- a/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs @@ -48,7 +48,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); + var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); editor.Generator.SyntaxFacts.GetPartsOfConditionalExpression(conditional, out var condition, out var whenTrue, out var whenFalse); diff --git a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs index 54e833204b764..8d1660ba3edfd 100644 --- a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs +++ b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs @@ -80,12 +80,19 @@ public override void VisitNamedType(INamedTypeSymbol symbol) if (_seenTypes.Add(symbol)) { - if (symbol.IsNormalAnonymousType()) + if (symbol.IsAnonymousType()) { _namedTypes.Add(symbol, (order: _namedTypes.Count, count: 1)); - foreach (var property in symbol.GetValidAnonymousTypeProperties()) - property.Accept(this); + if (symbol.IsDelegateType()) + { + symbol.DelegateInvokeMethod?.Accept(this); + } + else + { + foreach (var property in symbol.GetValidAnonymousTypeProperties()) + property.Accept(this); + } } else if (symbol.IsTupleType) { @@ -94,10 +101,6 @@ public override void VisitNamedType(INamedTypeSymbol symbol) foreach (var field in symbol.TupleElements) field.Accept(this); } - else if (symbol.IsAnonymousDelegateType()) - { - symbol.DelegateInvokeMethod?.Accept(this); - } else { foreach (var typeArgument in symbol.GetAllTypeArguments()) diff --git a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.cs b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.cs index 00ded8aab1dba..40c5f5ea28062 100644 --- a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.cs +++ b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServices @@ -15,8 +16,50 @@ internal abstract partial class AbstractStructuralTypeDisplayService : IStructur protected static readonly SymbolDisplayFormat s_minimalWithoutExpandedTuples = SymbolDisplayFormat.MinimallyQualifiedFormat.AddMiscellaneousOptions( SymbolDisplayMiscellaneousOptions.CollapseTupleTypes); - public abstract ImmutableArray GetAnonymousTypeParts( - INamedTypeSymbol anonymousType, SemanticModel semanticModel, int position); + private static readonly SymbolDisplayFormat s_delegateDisplay = + s_minimalWithoutExpandedTuples.WithMemberOptions(s_minimalWithoutExpandedTuples.MemberOptions & ~SymbolDisplayMemberOptions.IncludeContainingType); + + protected abstract ISyntaxFacts SyntaxFactsService { get; } + protected abstract ImmutableArray GetNormalAnonymousTypeParts(INamedTypeSymbol anonymousType, SemanticModel semanticModel, int position); + + public ImmutableArray GetAnonymousTypeParts(INamedTypeSymbol anonymousType, SemanticModel semanticModel, int position) + => anonymousType.IsAnonymousDelegateType() + ? GetDelegateAnonymousTypeParts(anonymousType, semanticModel, position) + : GetNormalAnonymousTypeParts(anonymousType, semanticModel, position); + + private ImmutableArray GetDelegateAnonymousTypeParts( + INamedTypeSymbol anonymousType, + SemanticModel semanticModel, + int position) + { + using var _ = ArrayBuilder.GetInstance(out var parts); + + var invokeMethod = anonymousType.DelegateInvokeMethod ?? throw ExceptionUtilities.Unreachable; + + parts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.Keyword, symbol: null, + SyntaxFactsService.GetText(SyntaxFactsService.SyntaxKinds.DelegateKeyword))); + parts.AddRange(Space()); + parts.AddRange(MassageDelegateParts(invokeMethod, invokeMethod.ToMinimalDisplayParts( + semanticModel, position, s_delegateDisplay))); + + return parts.ToImmutable(); + } + + private static ImmutableArray MassageDelegateParts( + IMethodSymbol invokeMethod, + ImmutableArray parts) + { + using var _ = ArrayBuilder.GetInstance(out var result); + + // Ugly hack. Remove the "Invoke" name the compiler layer adds to the parts. + foreach (var part in parts) + { + if (!Equals(invokeMethod, part.Symbol)) + result.Add(part); + } + + return result.ToImmutable(); + } public StructuralTypeDisplayInfo GetTypeDisplayInfo( ISymbol orderSymbol, @@ -47,9 +90,12 @@ public StructuralTypeDisplayInfo GetTypeDisplayInfo( var structuralType = transitiveStructuralTypeReferences[i]; typeParts.AddRange(Space(count: 4)); - typeParts.Add(Part( - structuralType.IsValueType ? SymbolDisplayPartKind.StructName : SymbolDisplayPartKind.ClassName, - structuralType, structuralType.Name)); + + var kind = + structuralType.IsValueType ? SymbolDisplayPartKind.StructName : + structuralType.IsDelegateType() ? SymbolDisplayPartKind.DelegateName : SymbolDisplayPartKind.ClassName; + + typeParts.Add(Part(kind, structuralType, structuralType.Name)); typeParts.AddRange(Space()); typeParts.Add(PlainText(FeaturesResources.is_)); typeParts.AddRange(Space()); @@ -64,9 +110,6 @@ public StructuralTypeDisplayInfo GetTypeDisplayInfo( } } - // Now, inline any delegate anonymous types we've got. - typeParts = this.InlineDelegateAnonymousTypes(typeParts, semanticModel, position); - // Finally, assign a name to all the anonymous types. var structuralTypeToName = GenerateStructuralTypeNames(transitiveStructuralTypeReferences); typeParts = StructuralTypeDisplayInfo.ReplaceStructuralTypes( diff --git a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/IStructuralTypeDisplayServiceExtensions.cs b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/IStructuralTypeDisplayServiceExtensions.cs deleted file mode 100644 index 8f41b1b3c83df..0000000000000 --- a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/IStructuralTypeDisplayServiceExtensions.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.LanguageServices -{ - internal static class IStructuralTypeDisplayServiceExtensions - { - public static IList InlineDelegateAnonymousTypes( - this IStructuralTypeDisplayService service, IList parts, SemanticModel semanticModel, int position) - { - var result = parts; - while (true) - { - var delegateAnonymousType = result.Select(p => p.Symbol).OfType().FirstOrDefault(s => s.IsAnonymousDelegateType()); - if (delegateAnonymousType == null) - { - break; - } - - result = result == parts ? new List(parts) : result; - ReplaceAnonymousType(result, delegateAnonymousType, - service.GetAnonymousTypeParts(delegateAnonymousType, semanticModel, position)); - } - - return result; - } - - private static void ReplaceAnonymousType( - IList list, - INamedTypeSymbol anonymousType, - IEnumerable parts) - { - var index = list.IndexOf(p => anonymousType.Equals(p.Symbol)); - if (index >= 0) - { - var result = list.Take(index).Concat(parts).Concat(list.Skip(index + 1)).ToList(); - list.Clear(); - list.AddRange(result); - } - } - } -} diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs index 7575bf0b5726b..4a9243b65f3b1 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -17,24 +14,20 @@ protected abstract partial class AbstractSymbolDescriptionBuilder { private void FixAllStructuralTypes(ISymbol firstSymbol) { - // First, inline all the delegate anonymous types. This is how VB prefers to display - // things. - InlineAllDelegateAnonymousTypes(_semanticModel, _position, _structuralTypeDisplayService, _groupMap); - // Now, replace all normal anonymous types and tuples with 'a, 'b, etc. and create a // Structural Types: section to display their info. - FixStructuralTypes(firstSymbol); - } - - protected abstract void InlineAllDelegateAnonymousTypes(SemanticModel semanticModel, int position, IStructuralTypeDisplayService structuralTypeDisplayService, Dictionary> groupMap); - private void FixStructuralTypes(ISymbol firstSymbol) - { var directStructuralTypes = from parts in _groupMap.Values from part in parts - where part.Symbol.IsNormalAnonymousType() || part.Symbol.IsTupleType() - select (INamedTypeSymbol)part.Symbol; + where part.Symbol.IsAnonymousType() || part.Symbol.IsTupleType() + select (INamedTypeSymbol)part.Symbol!; + + // If the first symbol is an anonymous delegate, just show it's full sig in-line in the main + // description. Otherwise, replace it with 'a, 'b etc. and show its sig in the 'Types:' section. + + if (firstSymbol.IsAnonymousDelegateType()) + directStructuralTypes = directStructuralTypes.Except(new[] { (INamedTypeSymbol)firstSymbol }); var info = _structuralTypeDisplayService.GetTypeDisplayInfo( firstSymbol, directStructuralTypes.ToImmutableArrayOrEmpty(), _semanticModel, _position); diff --git a/src/EditorFeatures/Core/ILineSeparatorService.cs b/src/Features/Core/Portable/LineSeparators/ILineSeparatorService.cs similarity index 63% rename from src/EditorFeatures/Core/ILineSeparatorService.cs rename to src/Features/Core/Portable/LineSeparators/ILineSeparatorService.cs index 131549ddc46d6..254fce9be39c9 100644 --- a/src/EditorFeatures/Core/ILineSeparatorService.cs +++ b/src/Features/Core/Portable/LineSeparators/ILineSeparatorService.cs @@ -2,18 +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. -#nullable disable - -using System.Collections.Generic; +using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Editor +namespace Microsoft.CodeAnalysis.LineSeparators { internal interface ILineSeparatorService : ILanguageService { - Task> GetLineSeparatorsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken = default); + Task> GetLineSeparatorsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs index 75a120ea05a01..4e70c8f267af3 100644 --- a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs +++ b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs @@ -168,7 +168,7 @@ private async Task RenameThenAddAsyncTokenAsync( var syntaxPath = new SyntaxPath(node); // Rename the method to add the 'Async' suffix, then add the 'async' keyword. - var newSolution = await Renamer.RenameSymbolAsync(solution, methodSymbol, newName, solution.Options, cancellationToken).ConfigureAwait(false); + var newSolution = await Renamer.RenameSymbolAsync(solution, methodSymbol, new SymbolRenameOptions(), newName, cancellationToken).ConfigureAwait(false); var newDocument = newSolution.GetDocument(document.Id); var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs index 1d05148dcdcbe..2719460e484ad 100644 --- a/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs +++ b/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs @@ -77,7 +77,7 @@ private async Task RenameThenRemoveAsyncTokenAsync(Document document, var syntaxPath = new SyntaxPath(node); // Rename the method to remove the 'Async' suffix, then remove the 'async' keyword. - var newSolution = await Renamer.RenameSymbolAsync(solution, methodSymbol, newName, solution.Options, cancellationToken).ConfigureAwait(false); + var newSolution = await Renamer.RenameSymbolAsync(solution, methodSymbol, new SymbolRenameOptions(), newName, cancellationToken).ConfigureAwait(false); var newDocument = newSolution.GetDocument(document.Id); var newRoot = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (syntaxPath.TryResolve(newRoot, out SyntaxNode newNode)) @@ -164,7 +164,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); + var editor = new SyntaxEditor(root, currentSolution.Workspace.Services); foreach (var location in group) { diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs index 7a8ecdfd63b06..3854307a217fc 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs @@ -34,14 +34,19 @@ public async Task AddSourceToAsync(Document document, Compilation symb var newSemanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var rootNamespace = newSemanticModel.GetEnclosingNamespace(0, cancellationToken); - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); + var context = new CodeGenerationContext( + contextLocation: newSemanticModel.SyntaxTree.GetLocation(new TextSpan()), + generateMethodBodies: false, + generateDocumentationComments: true, + mergeAttributes: false, + autoInsertionLocation: false); // Add the interface of the symbol to the top of the root namespace document = await CodeGenerator.AddNamespaceOrTypeDeclarationAsync( document.Project.Solution, rootNamespace, CreateCodeGenerationSymbol(document, symbol), - CreateCodeGenerationOptions(newSemanticModel.SyntaxTree.GetLocation(new TextSpan()), options), + context, cancellationToken).ConfigureAwait(false); document = await AddNullableRegionsAsync(document, cancellationToken).ConfigureAwait(false); @@ -51,8 +56,14 @@ public async Task AddSourceToAsync(Document document, Compilation symb var docWithAssemblyInfo = await AddAssemblyInfoRegionAsync(docWithDocComments, symbolCompilation, symbol.GetOriginalUnreducedDefinition(), cancellationToken).ConfigureAwait(false); var node = await docWithAssemblyInfo.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var options = await SyntaxFormattingOptions.FromDocumentAsync(docWithAssemblyInfo, cancellationToken).ConfigureAwait(false); + var formattedDoc = await Formatter.FormatAsync( - docWithAssemblyInfo, SpecializedCollections.SingletonEnumerable(node.FullSpan), options: null, rules: GetFormattingRules(docWithAssemblyInfo), cancellationToken: cancellationToken).ConfigureAwait(false); + docWithAssemblyInfo, + SpecializedCollections.SingletonEnumerable(node.FullSpan), + options, + GetFormattingRules(docWithAssemblyInfo), + cancellationToken).ConfigureAwait(false); var reducers = GetReducers(); return await Simplifier.ReduceAsync(formattedDoc, reducers, null, cancellationToken).ConfigureAwait(false); @@ -101,16 +112,5 @@ private static INamespaceOrTypeSymbol CreateCodeGenerationSymbol(Document docume null, new[] { wrappedType }); } - - private static CodeGenerationOptions CreateCodeGenerationOptions(Location contextLocation, OptionSet options) - { - return new CodeGenerationOptions( - contextLocation: contextLocation, - generateMethodBodies: false, - generateDocumentationComments: true, - mergeAttributes: false, - autoInsertionLocation: false, - options: options); - } } } diff --git a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj index 0d40e2fb88215..7cda913db91b8 100644 --- a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj +++ b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj @@ -29,6 +29,7 @@ + @@ -55,6 +56,7 @@ + - - - Library - Roslyn.Hosting.Diagnostics - net472 - true - - - - - - - - - - - - - - - - - - diff --git a/src/Tools/AnalyzerRunner/Options.cs b/src/Tools/AnalyzerRunner/Options.cs index 2e7bd8d9662e6..6ea3f3ce87719 100644 --- a/src/Tools/AnalyzerRunner/Options.cs +++ b/src/Tools/AnalyzerRunner/Options.cs @@ -40,7 +40,7 @@ public sealed class Options internal readonly string ProfileRoot; internal BackgroundAnalysisScope AnalysisScope - => FullSolutionAnalysis ? BackgroundAnalysisScope.FullSolution : BackgroundAnalysisScope.Default; + => FullSolutionAnalysis ? BackgroundAnalysisScope.FullSolution : BackgroundAnalysisScope.OpenFiles; public Options( string analyzerPath, diff --git a/src/Tools/BuildActionTelemetryTable/BuildActionTelemetryTable.csproj b/src/Tools/BuildActionTelemetryTable/BuildActionTelemetryTable.csproj index 59bb965db17ed..b1c94c56fa23d 100644 --- a/src/Tools/BuildActionTelemetryTable/BuildActionTelemetryTable.csproj +++ b/src/Tools/BuildActionTelemetryTable/BuildActionTelemetryTable.csproj @@ -20,11 +20,14 @@ + + + diff --git a/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs b/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs index 15087e29c0cc7..90d8e051795ac 100644 --- a/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs +++ b/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs @@ -20,7 +20,7 @@ namespace BuildBoss /// /// Verifies the contents of our toolset NuPkg and SWR files are correct. /// - /// The compiler toolset is a particularly difficult package to get correct. In essense it is + /// The compiler toolset is a particularly difficult package to get correct. In essence it is /// merging the output of three different exes into a single directory. That causes a number /// of issues during pack time: /// diff --git a/src/Tools/BuildValidator/Program.cs b/src/Tools/BuildValidator/Program.cs index 63915f3292d52..609b95eef9a0f 100644 --- a/src/Tools/BuildValidator/Program.cs +++ b/src/Tools/BuildValidator/Program.cs @@ -72,6 +72,7 @@ static int HandleCommand(string[] assembliesPath, string[]? exclude, string sour var excludes = new List(exclude ?? Array.Empty()); excludes.Add(Path.DirectorySeparatorChar + "runtimes" + Path.DirectorySeparatorChar); excludes.Add(Path.DirectorySeparatorChar + "ref" + Path.DirectorySeparatorChar); + excludes.Add(Path.DirectorySeparatorChar + "refint" + Path.DirectorySeparatorChar); excludes.Add(@".resources.dll"); var options = new Options(assembliesPath, referencesPath, excludes.ToArray(), sourcePath, verbose, quiet, debug, debugPath); diff --git a/src/Tools/ExternalAccess/Debugger/DebuggerFindReferencesService.cs b/src/Tools/ExternalAccess/Debugger/DebuggerFindReferencesService.cs index c7526f1d34bc8..7dd11892a818f 100644 --- a/src/Tools/ExternalAccess/Debugger/DebuggerFindReferencesService.cs +++ b/src/Tools/ExternalAccess/Debugger/DebuggerFindReferencesService.cs @@ -7,9 +7,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.ExternalAccess.Debugger diff --git a/src/Tools/ExternalAccess/Debugger/GlassTestsHotReloadService.cs b/src/Tools/ExternalAccess/Debugger/GlassTestsHotReloadService.cs new file mode 100644 index 0000000000000..32e0797a8366e --- /dev/null +++ b/src/Tools/ExternalAccess/Debugger/GlassTestsHotReloadService.cs @@ -0,0 +1,116 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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.EditAndContinue; +using Microsoft.CodeAnalysis.Editor.Implementation.EditAndContinue; +using Microsoft.CodeAnalysis.Host; +using Microsoft.VisualStudio.Debugger.Contracts.EditAndContinue; +using Microsoft.VisualStudio.Debugger.Contracts.HotReload; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Debugger +{ + internal sealed class GlassTestsHotReloadService + { + private static readonly ActiveStatementSpanProvider s_noActiveStatementSpanProvider = + (_, _, _) => ValueTaskFactory.FromResult(ImmutableArray.Empty); + + private readonly IManagedHotReloadService _debuggerService; + + private readonly IEditAndContinueWorkspaceService _encService; + private DebuggingSessionId _sessionId; + + public GlassTestsHotReloadService(HostWorkspaceServices services, IManagedHotReloadService debuggerService) + { + _encService = services.GetRequiredService(); + _debuggerService = debuggerService; + } + + public async Task StartSessionAsync(Solution solution, CancellationToken cancellationToken) + { + var newSessionId = await _encService.StartDebuggingSessionAsync( + solution, + new ManagedHotReloadServiceImpl(_debuggerService), + captureMatchingDocuments: ImmutableArray.Empty, + captureAllMatchingDocuments: true, + reportDiagnostics: false, + cancellationToken).ConfigureAwait(false); + + Contract.ThrowIfFalse(_sessionId == default, "Session already started"); + _sessionId = newSessionId; + } + + private DebuggingSessionId GetSessionId() + { + var sessionId = _sessionId; + Contract.ThrowIfFalse(sessionId != default, "Session has not started"); + + return sessionId; + } + + public void EnterBreakState() + { + _encService.BreakStateOrCapabilitiesChanged(GetSessionId(), inBreakState: true, out _); + } + + public void ExitBreakState() + { + _encService.BreakStateOrCapabilitiesChanged(GetSessionId(), inBreakState: false, out _); + } + + public void OnCapabilitiesChanged() + { + _encService.BreakStateOrCapabilitiesChanged(GetSessionId(), inBreakState: null, out _); + } + + public void CommitSolutionUpdate() + { + _encService.CommitSolutionUpdate(GetSessionId(), out _); + } + + public void DiscardSolutionUpdate() + { + _encService.DiscardSolutionUpdate(GetSessionId()); + } + + public void EndDebuggingSession() + { + _encService.EndDebuggingSession(GetSessionId(), out _); + _sessionId = default; + } + + public async ValueTask HasChangesAsync(Solution solution, string? sourceFilePath, CancellationToken cancellationToken) + { + var sessionId = _sessionId; + if (sessionId == default) + { + return false; + } + + return await _encService.HasChangesAsync(sessionId, solution, s_noActiveStatementSpanProvider, sourceFilePath, cancellationToken).ConfigureAwait(false); + } + + 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) + { + 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()); + } + } +} diff --git a/src/Tools/ExternalAccess/Debugger/Microsoft.CodeAnalysis.ExternalAccess.Debugger.csproj b/src/Tools/ExternalAccess/Debugger/Microsoft.CodeAnalysis.ExternalAccess.Debugger.csproj index ffa1250dac7da..26415884a85b0 100644 --- a/src/Tools/ExternalAccess/Debugger/Microsoft.CodeAnalysis.ExternalAccess.Debugger.csproj +++ b/src/Tools/ExternalAccess/Debugger/Microsoft.CodeAnalysis.ExternalAccess.Debugger.csproj @@ -20,6 +20,7 @@ ⚠ ONLY VISUAL STUDIO DEBUGGER ASSEMBLIES MAY BE ADDED HERE ⚠ --> + @@ -29,6 +30,7 @@ + diff --git a/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs b/src/Tools/ExternalAccess/FSharp/Completion/FSharpCompletionProviderBase.cs index 7d6df62af8283..1220da8e2a3a1 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) + internal sealed override bool ShouldTriggerCompletion(HostLanguageServices 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/Editor/IFSharpEditorInlineRenameService.cs b/src/Tools/ExternalAccess/FSharp/Editor/IFSharpEditorInlineRenameService.cs index 7041deec76cac..fc2346566e0b8 100644 --- a/src/Tools/ExternalAccess/FSharp/Editor/IFSharpEditorInlineRenameService.cs +++ b/src/Tools/ExternalAccess/FSharp/Editor/IFSharpEditorInlineRenameService.cs @@ -4,6 +4,7 @@ #nullable disable +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -13,41 +14,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor { - internal readonly struct FSharpInlineRenameLocation - { - public Document Document { get; } - public TextSpan TextSpan { get; } - - public FSharpInlineRenameLocation(Document document, TextSpan textSpan) - { - this.Document = document; - this.TextSpan = textSpan; - } - } - - internal enum FSharpInlineRenameReplacementKind - { - NoConflict, - ResolvedReferenceConflict, - ResolvedNonReferenceConflict, - UnresolvedConflict, - Complexified, - } - - internal readonly struct FSharpInlineRenameReplacement - { - public FSharpInlineRenameReplacementKind Kind { get; } - public TextSpan OriginalSpan { get; } - public TextSpan NewSpan { get; } - - public FSharpInlineRenameReplacement(FSharpInlineRenameReplacementKind kind, TextSpan originalSpan, TextSpan newSpan) - { - this.Kind = kind; - this.OriginalSpan = originalSpan; - this.NewSpan = newSpan; - } - } - + [Obsolete] internal interface IFSharpInlineRenameReplacementInfo { /// @@ -71,6 +38,7 @@ internal interface IFSharpInlineRenameReplacementInfo IEnumerable GetReplacements(DocumentId documentId); } + [Obsolete] internal interface IFSharpInlineRenameLocationSet { /// @@ -89,6 +57,7 @@ internal interface IFSharpInlineRenameLocationSet Task GetReplacementsAsync(string replacementText, OptionSet optionSet, CancellationToken cancellationToken); } + [Obsolete] internal interface IFSharpInlineRenameInfo { /// @@ -175,6 +144,7 @@ internal interface IFSharpInlineRenameInfo /// /// Language service that allows a language to participate in the editor's inline rename feature. /// + [Obsolete] internal interface IFSharpEditorInlineRenameService { Task GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken); diff --git a/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs new file mode 100644 index 0000000000000..64e1ca6da91d2 --- /dev/null +++ b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameInfo.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +{ + internal abstract class FSharpInlineRenameInfo : IInlineRenameInfo + { + public abstract bool CanRename { get; } + public abstract string DisplayName { get; } + public abstract string FullDisplayName { get; } + public abstract FSharpGlyph Glyph { get; } + public abstract bool HasOverloads { get; } + public abstract bool ForceRenameOverloads { get; } + public abstract string LocalizedErrorMessage { get; } + public abstract TextSpan TriggerSpan { get; } + public abstract ImmutableArray DefinitionLocations { get; } + public abstract Task FindRenameLocationsAsync(bool renameInStrings, bool renameInComments, CancellationToken cancellationToken); + public abstract TextSpan? GetConflictEditSpan(FSharpInlineRenameLocation location, string replacementText, CancellationToken cancellationToken); + public abstract string GetFinalSymbolName(string replacementText); + public abstract TextSpan GetReferenceEditSpan(FSharpInlineRenameLocation location, CancellationToken cancellationToken); + + Glyph IInlineRenameInfo.Glyph + => FSharpGlyphHelpers.ConvertTo(Glyph); + + bool IInlineRenameInfo.MustRenameOverloads + => ForceRenameOverloads; + + ImmutableArray IInlineRenameInfo.DefinitionLocations + => DefinitionLocations.SelectAsArray(l => new DocumentSpan(l.Document, l.TextSpan)); + + async Task IInlineRenameInfo.FindRenameLocationsAsync(SymbolRenameOptions options, CancellationToken cancellationToken) + => await FindRenameLocationsAsync( + options.RenameInStrings, + options.RenameInComments, + cancellationToken).ConfigureAwait(false); + + TextSpan? IInlineRenameInfo.GetConflictEditSpan(InlineRenameLocation location, string triggerText, string replacementText, CancellationToken cancellationToken) + => GetConflictEditSpan(new FSharpInlineRenameLocation(location.Document, location.TextSpan), replacementText, cancellationToken); + + TextSpan IInlineRenameInfo.GetReferenceEditSpan(InlineRenameLocation location, string triggerText, CancellationToken cancellationToken) + => GetReferenceEditSpan(new FSharpInlineRenameLocation(location.Document, location.TextSpan), cancellationToken); + + bool IInlineRenameInfo.TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) + => true; + + bool IInlineRenameInfo.TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, string replacementText) + => true; + } +} diff --git a/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocation.cs b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocation.cs new file mode 100644 index 0000000000000..bb7fadd347527 --- /dev/null +++ b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocation.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. + +#nullable disable + +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +{ + internal readonly struct FSharpInlineRenameLocation + { + public Document Document { get; } + public TextSpan TextSpan { get; } + + public FSharpInlineRenameLocation(Document document, TextSpan textSpan) + { + this.Document = document; + this.TextSpan = textSpan; + } + } +} diff --git a/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocationSet.cs b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocationSet.cs new file mode 100644 index 0000000000000..dc6bb255efc47 --- /dev/null +++ b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameLocationSet.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. + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; + +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +{ + internal abstract class FSharpInlineRenameLocationSet : IInlineRenameLocationSet + { + /// + /// The set of locations that need to be updated with the replacement text that the user + /// has entered in the inline rename session. These are the locations are all relative + /// to the solution when the inline rename session began. + /// + public abstract IList Locations { get; } + + IList IInlineRenameLocationSet.Locations + => Locations?.Select(x => new InlineRenameLocation(x.Document, x.TextSpan)).ToList(); + + /// + /// Returns the set of replacements and their possible resolutions if the user enters the + /// provided replacement text and options. Replacements are keyed by their document id + /// and TextSpan in the original solution, and specify their new span and possible conflict + /// resolution. + /// + public abstract Task GetReplacementsAsync(string replacementText, CancellationToken cancellationToken); + + async Task IInlineRenameLocationSet.GetReplacementsAsync(string replacementText, SymbolRenameOptions options, CancellationToken cancellationToken) + => await GetReplacementsAsync(replacementText, cancellationToken).ConfigureAwait(false); + } +} diff --git a/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacement.cs b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacement.cs new file mode 100644 index 0000000000000..c437c15517372 --- /dev/null +++ b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacement.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +{ + internal readonly struct FSharpInlineRenameReplacement + { + public FSharpInlineRenameReplacementKind Kind { get; } + public TextSpan OriginalSpan { get; } + public TextSpan NewSpan { get; } + + public FSharpInlineRenameReplacement(FSharpInlineRenameReplacementKind kind, TextSpan originalSpan, TextSpan newSpan) + { + this.Kind = kind; + this.OriginalSpan = originalSpan; + this.NewSpan = newSpan; + } + } +} diff --git a/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementInfo.cs b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementInfo.cs new file mode 100644 index 0000000000000..035d18ef86c94 --- /dev/null +++ b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementInfo.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Editor; + +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +{ + internal abstract class FSharpInlineRenameReplacementInfo : IInlineRenameReplacementInfo + { + /// + /// The solution obtained after resolving all conflicts. + /// + public abstract Solution NewSolution { get; } + + /// + /// Whether or not the replacement text entered by the user is valid. + /// + public abstract bool ReplacementTextValid { get; } + + /// + /// The documents that need to be updated. + /// + public abstract IEnumerable DocumentIds { get; } + + /// + /// Returns all the replacements that need to be performed for the specified document. + /// + public abstract IEnumerable GetReplacements(DocumentId documentId); + + IEnumerable IInlineRenameReplacementInfo.GetReplacements(DocumentId documentId) + => GetReplacements(documentId).Select(r => new InlineRenameReplacement(FSharpInlineRenameReplacementKindHelpers.ConvertTo(r.Kind), r.OriginalSpan, r.NewSpan)); + } +} diff --git a/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementKind.cs b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementKind.cs new file mode 100644 index 0000000000000..ea81beb3c5d29 --- /dev/null +++ b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameReplacementKind.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. + +#nullable disable + +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +{ + internal enum FSharpInlineRenameReplacementKind + { + NoConflict, + ResolvedReferenceConflict, + ResolvedNonReferenceConflict, + UnresolvedConflict, + Complexified, + } +} diff --git a/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameServiceImplementation.cs b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameServiceImplementation.cs new file mode 100644 index 0000000000000..f853f189b494d --- /dev/null +++ b/src/Tools/ExternalAccess/FSharp/Editor/InlineRename/FSharpInlineRenameServiceImplementation.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor +{ + internal abstract class FSharpInlineRenameServiceImplementation + { + public abstract Task GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken); + } +} diff --git a/src/Tools/ExternalAccess/FSharp/FSharpEditorFeaturesResources.cs b/src/Tools/ExternalAccess/FSharp/FSharpEditorFeaturesResources.cs index 9b0a0169f383b..ead5781134856 100644 --- a/src/Tools/ExternalAccess/FSharp/FSharpEditorFeaturesResources.cs +++ b/src/Tools/ExternalAccess/FSharp/FSharpEditorFeaturesResources.cs @@ -4,10 +4,12 @@ #nullable disable +using System; using Microsoft.CodeAnalysis.Editor; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp { + [Obsolete] internal static class FSharpEditorFeaturesResources { public static string You_cannot_rename_this_element => EditorFeaturesResources.You_cannot_rename_this_element; diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs index b551a058854ed..05736e9b16964 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorFormattingService.cs @@ -57,7 +57,7 @@ public Task> GetFormattingChangesOnPasteAsync(Document documen return _service.GetFormattingChangesOnReturnAsync(document, position, cancellationToken); } - public bool SupportsFormattingOnTypedCharacter(Document document, char ch) + public bool SupportsFormattingOnTypedCharacter(Document document, AutoFormattingOptions options, char ch) { return _service.SupportsFormattingOnTypedCharacter(document, ch); } diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs index 0f645ef1565e3..43c3325d4fc9d 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs @@ -7,16 +7,17 @@ using System; using System.Linq; using System.Collections.Generic; +using System.Collections.Immutable; using System.Composition; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Editor { @@ -59,11 +60,12 @@ public static InlineRenameReplacementKind ConvertTo(FSharpInlineRenameReplacemen } } - internal class FSharpInlineRenameReplacementInfo : IInlineRenameReplacementInfo + [Obsolete] + internal class FSharpInlineRenameReplacementInfoLegacyWrapper : IInlineRenameReplacementInfo { private readonly IFSharpInlineRenameReplacementInfo _info; - public FSharpInlineRenameReplacementInfo(IFSharpInlineRenameReplacementInfo info) + public FSharpInlineRenameReplacementInfoLegacyWrapper(IFSharpInlineRenameReplacementInfo info) { _info = info; } @@ -81,12 +83,13 @@ public IEnumerable GetReplacements(DocumentId documentI } } - internal class FSharpInlineRenameLocationSet : IInlineRenameLocationSet + [Obsolete] + internal class FSharpInlineRenameLocationSetLegacyWrapper : IInlineRenameLocationSet { private readonly IFSharpInlineRenameLocationSet _set; private readonly IList _locations; - public FSharpInlineRenameLocationSet(IFSharpInlineRenameLocationSet set) + public FSharpInlineRenameLocationSetLegacyWrapper(IFSharpInlineRenameLocationSet set) { _set = set; _locations = set.Locations?.Select(x => new InlineRenameLocation(x.Document, x.TextSpan)).ToList(); @@ -94,12 +97,12 @@ public FSharpInlineRenameLocationSet(IFSharpInlineRenameLocationSet set) public IList Locations => _locations; - public async Task GetReplacementsAsync(string replacementText, OptionSet optionSet, CancellationToken cancellationToken) + public async Task GetReplacementsAsync(string replacementText, SymbolRenameOptions options, CancellationToken cancellationToken) { - var info = await _set.GetReplacementsAsync(replacementText, optionSet, cancellationToken).ConfigureAwait(false); + var info = await _set.GetReplacementsAsync(replacementText, optionSet: null, cancellationToken).ConfigureAwait(false); if (info != null) { - return new FSharpInlineRenameReplacementInfo(info); + return new FSharpInlineRenameReplacementInfoLegacyWrapper(info); } else { @@ -108,11 +111,12 @@ public async Task GetReplacementsAsync(string repl } } - internal class FSharpInlineRenameInfo : IInlineRenameInfo + [Obsolete] + internal class FSharpInlineRenameInfoLegacyWrapper : IInlineRenameInfo { private readonly IFSharpInlineRenameInfo _info; - public FSharpInlineRenameInfo(IFSharpInlineRenameInfo info) + public FSharpInlineRenameInfoLegacyWrapper(IFSharpInlineRenameInfo info) { _info = info; } @@ -125,7 +129,7 @@ public FSharpInlineRenameInfo(IFSharpInlineRenameInfo info) public bool HasOverloads => _info.HasOverloads; - public bool ForceRenameOverloads => _info.ForceRenameOverloads; + public bool MustRenameOverloads => _info.ForceRenameOverloads; public string DisplayName => _info.DisplayName; @@ -136,12 +140,12 @@ public FSharpInlineRenameInfo(IFSharpInlineRenameInfo info) // This property isn't currently supported in F# since it would involve modifying the IFSharpInlineRenameInfo interface. public ImmutableArray DefinitionLocations => default; - public async Task FindRenameLocationsAsync(OptionSet optionSet, CancellationToken cancellationToken) + public async Task FindRenameLocationsAsync(SymbolRenameOptions options, CancellationToken cancellationToken) { - var set = await _info.FindRenameLocationsAsync(optionSet, cancellationToken).ConfigureAwait(false); + var set = await _info.FindRenameLocationsAsync(optionSet: null, cancellationToken).ConfigureAwait(false); if (set != null) { - return new FSharpInlineRenameLocationSet(set); + return new FSharpInlineRenameLocationSetLegacyWrapper(set); } else { @@ -175,30 +179,42 @@ public bool TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken) { - var info = await _service.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false); - if (info != null) +#pragma warning disable CS0612 // Type or member is obsolete + if (_legacyService != null) { - return new FSharpInlineRenameInfo(info); + var info = await _legacyService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false); + return (info != null) ? new FSharpInlineRenameInfoLegacyWrapper(info) : AbstractEditorInlineRenameService.DefaultFailureInfo; } - else +#pragma warning restore CS0612 // Type or member is obsolete + + if (_service != null) { - return null; + return await _service.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false) ?? AbstractEditorInlineRenameService.DefaultFailureInfo; } + + return AbstractEditorInlineRenameService.DefaultFailureInfo; } } } diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs index 94645d0814722..14877a92a0d36 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FSharpNavigationBarItemService.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.Notification; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -62,7 +63,7 @@ public async Task TryNavigateToItemAsync( if (navigationService.CanNavigateToPosition(workspace, document.Id, span.Start, virtualSpace: 0, cancellationToken)) { - navigationService.TryNavigateToPosition(workspace, document.Id, span.Start, virtualSpace: 0, options: null, cancellationToken); + navigationService.TryNavigateToPosition(workspace, document.Id, span.Start, virtualSpace: 0, cancellationToken); } else { diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesService.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesService.cs index 623dda3cb550c..a742ec2c7facd 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesService.cs @@ -6,7 +6,6 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.FindUsages; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; @@ -15,7 +14,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Editor.FindUsage { [Shared] [ExportLanguageService(typeof(IFindUsagesService), LanguageNames.FSharp)] - internal class FSharpFindUsagesService : IFindUsagesService + internal sealed class FSharpFindUsagesService : IFindUsagesService { private readonly IFSharpFindUsagesService _service; @@ -24,10 +23,10 @@ internal class FSharpFindUsagesService : IFindUsagesService public FSharpFindUsagesService(IFSharpFindUsagesService service) => _service = service; - public Task FindImplementationsAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) + public Task FindImplementationsAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) => _service.FindImplementationsAsync(document, position, new FSharpFindUsagesContext(context, cancellationToken)); - public Task FindReferencesAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) + public Task FindReferencesAsync(IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken) => _service.FindReferencesAsync(document, position, new FSharpFindUsagesContext(context, cancellationToken)); } } diff --git a/src/Tools/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj b/src/Tools/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj index 3d8e45905efa5..d0964c328354a 100644 --- a/src/Tools/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj +++ b/src/Tools/ExternalAccess/FSharp/Microsoft.CodeAnalysis.ExternalAccess.FSharp.csproj @@ -38,6 +38,10 @@ + + + + diff --git a/src/Tools/ExternalAccess/FSharp/Navigation/FSharpDocumentNavigationService.cs b/src/Tools/ExternalAccess/FSharp/Navigation/FSharpDocumentNavigationService.cs index fe5b89d198a1a..942c3eb3199b1 100644 --- a/src/Tools/ExternalAccess/FSharp/Navigation/FSharpDocumentNavigationService.cs +++ b/src/Tools/ExternalAccess/FSharp/Navigation/FSharpDocumentNavigationService.cs @@ -23,6 +23,7 @@ public FSharpDocumentNavigationService() { } + [Obsolete("Call overload that takes a CancellationToken", error: false)] public bool CanNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan) => CanNavigateToSpan(workspace, documentId, textSpan, CancellationToken.None); @@ -32,6 +33,7 @@ public bool CanNavigateToSpan(Workspace workspace, DocumentId documentId, TextSp return service.CanNavigateToSpan(workspace, documentId, textSpan, cancellationToken); } + [Obsolete("Call overload that takes a CancellationToken", error: false)] public bool CanNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset) => CanNavigateToLineAndOffset(workspace, documentId, lineNumber, offset, CancellationToken.None); @@ -41,6 +43,7 @@ public bool CanNavigateToLineAndOffset(Workspace workspace, DocumentId documentI return service.CanNavigateToLineAndOffset(workspace, documentId, lineNumber, offset, cancellationToken); } + [Obsolete("Call overload that takes a CancellationToken", error: false)] public bool CanNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace) => CanNavigateToPosition(workspace, documentId, position, virtualSpace, CancellationToken.None); @@ -50,31 +53,34 @@ public bool CanNavigateToPosition(Workspace workspace, DocumentId documentId, in return service.CanNavigateToPosition(workspace, documentId, position, virtualSpace, cancellationToken); } + [Obsolete("Call overload that takes a CancellationToken", error: false)] public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options) - => TryNavigateToSpan(workspace, documentId, textSpan, options, CancellationToken.None); + => TryNavigateToSpan(workspace, documentId, textSpan, CancellationToken.None); - public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, CancellationToken cancellationToken) + public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) { var service = workspace.Services.GetService(); - return service.TryNavigateToSpan(workspace, documentId, textSpan, options, cancellationToken); + return service.TryNavigateToSpan(workspace, documentId, textSpan, NavigationOptions.Default with { PreferProvisionalTab = true }, cancellationToken); } + [Obsolete("Call overload that takes a CancellationToken", error: false)] public bool TryNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset, OptionSet options) - => TryNavigateToLineAndOffset(workspace, documentId, lineNumber, offset, options, CancellationToken.None); + => TryNavigateToLineAndOffset(workspace, documentId, lineNumber, offset, CancellationToken.None); - public bool TryNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset, OptionSet options, CancellationToken cancellationToken) + public bool TryNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset, CancellationToken cancellationToken) { var service = workspace.Services.GetService(); - return service.TryNavigateToLineAndOffset(workspace, documentId, lineNumber, offset, options, cancellationToken); + return service.TryNavigateToLineAndOffset(workspace, documentId, lineNumber, offset, NavigationOptions.Default with { PreferProvisionalTab = true }, cancellationToken); } + [Obsolete("Call overload that takes a CancellationToken", error: false)] public bool TryNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, OptionSet options) - => TryNavigateToPosition(workspace, documentId, position, virtualSpace, options, CancellationToken.None); + => TryNavigateToPosition(workspace, documentId, position, virtualSpace, CancellationToken.None); - public bool TryNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, OptionSet options, CancellationToken cancellationToken) + public bool TryNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, CancellationToken cancellationToken) { var service = workspace.Services.GetService(); - return service.TryNavigateToPosition(workspace, documentId, position, virtualSpace, options, cancellationToken); + return service.TryNavigateToPosition(workspace, documentId, position, virtualSpace, NavigationOptions.Default with { PreferProvisionalTab = true }, cancellationToken); } } } diff --git a/src/Tools/ExternalAccess/FSharp/Navigation/FSharpNavigationOptions.cs b/src/Tools/ExternalAccess/FSharp/Navigation/FSharpNavigationOptions.cs index 461b0b5b9ccc2..be78a7396008c 100644 --- a/src/Tools/ExternalAccess/FSharp/Navigation/FSharpNavigationOptions.cs +++ b/src/Tools/ExternalAccess/FSharp/Navigation/FSharpNavigationOptions.cs @@ -4,13 +4,14 @@ #nullable disable -using Microsoft.CodeAnalysis.Navigation; +using System; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Navigation { + [Obsolete] internal static class FSharpNavigationOptions { - public static Option PreferProvisionalTab { get; } = (Option)NavigationOptions.PreferProvisionalTab; + public static Option PreferProvisionalTab { get; } = new("NavigationOptions", "PreferProvisionalTab", defaultValue: false); } } diff --git a/src/Tools/ExternalAccess/FSharp/Navigation/IFSharpDocumentNavigationService.cs b/src/Tools/ExternalAccess/FSharp/Navigation/IFSharpDocumentNavigationService.cs index 18f62b0ec3086..a14efe8244431 100644 --- a/src/Tools/ExternalAccess/FSharp/Navigation/IFSharpDocumentNavigationService.cs +++ b/src/Tools/ExternalAccess/FSharp/Navigation/IFSharpDocumentNavigationService.cs @@ -36,10 +36,10 @@ internal interface IFSharpDocumentNavigationService : IWorkspaceService bool CanNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, CancellationToken cancellationToken); /// - bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, CancellationToken cancellationToken); + bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken); /// - bool TryNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset, OptionSet options, CancellationToken cancellationToken); + bool TryNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset, CancellationToken cancellationToken); /// - bool TryNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, OptionSet options, CancellationToken cancellationToken); + bool TryNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, CancellationToken cancellationToken); } } diff --git a/src/Tools/ExternalAccess/OmniSharp/Completion/OmniSharpCompletionService.cs b/src/Tools/ExternalAccess/OmniSharp/Completion/OmniSharpCompletionService.cs index fb5c4d40c432b..ff4899c7fd774 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Completion/OmniSharpCompletionService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Completion/OmniSharpCompletionService.cs @@ -2,12 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Completion { @@ -23,10 +21,10 @@ 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(), roles); + return completionService.ShouldTriggerCompletion(document.Project, document.Project.LanguageServices, text, caretPosition, trigger, options.ToCompletionOptions(), document.Project.Solution.Options, roles); } - public static Task<(CompletionList? completionList, bool expandItemsAvailable)> GetCompletionsAsync( + public static Task GetCompletionsAsync( this CompletionService completionService, Document document, int caretPosition, @@ -34,7 +32,9 @@ public static async ValueTask ShouldTriggerCompletionAsync( ImmutableHashSet? roles, OmniSharpCompletionOptions options, CancellationToken cancellationToken) - => completionService.GetCompletionsInternalAsync(document, caretPosition, options.ToCompletionOptions(), trigger, roles, cancellationToken); + { + return completionService.GetCompletionsAsync(document, caretPosition, options.ToCompletionOptions(), document.Project.Solution.Options, trigger, roles, cancellationToken); + } public static string? GetProviderName(this CompletionItem completionItem) => completionItem.ProviderName; } diff --git a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs index a60eda3cfa1d3..6d4abad23938a 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractClass/OmniSharpExtractClassOptionsService.cs @@ -4,6 +4,7 @@ using System; using System.Composition; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ExtractClass; using Microsoft.CodeAnalysis.ExtractClass; @@ -24,7 +25,7 @@ public OmniSharpExtractClassOptionsService(IOmniSharpExtractClassOptionsService _omniSharpExtractClassOptionsService = omniSharpExtractClassOptionsService; } - public async Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalType, ISymbol? selectedMember) + public async Task GetExtractClassOptionsAsync(Document document, INamedTypeSymbol originalType, ISymbol? selectedMember, CancellationToken cancellationToken) { var result = await _omniSharpExtractClassOptionsService.GetExtractClassOptionsAsync(document, originalType, selectedMember).ConfigureAwait(false); return result == null diff --git a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs index ffcb263fbf3d4..08a2264ccfe8c 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Composition; using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ExtractInterface; using Microsoft.CodeAnalysis.ExtractInterface; @@ -28,7 +29,16 @@ public OmniSharpExtractInterfaceOptionsService(IOmniSharpExtractInterfaceOptions _omniSharpExtractInterfaceOptionsService = omniSharpExtractInterfaceOptionsService; } - public async Task GetExtractInterfaceOptionsAsync(ISyntaxFactsService syntaxFactsService, INotificationService notificationService, List extractableMembers, string defaultInterfaceName, List conflictingTypeNames, string defaultNamespace, string generatedNameTypeParameterSuffix, string languageName) + public async Task GetExtractInterfaceOptionsAsync( + ISyntaxFactsService syntaxFactsService, + INotificationService notificationService, + List extractableMembers, + string defaultInterfaceName, + List conflictingTypeNames, + string defaultNamespace, + string generatedNameTypeParameterSuffix, + string languageName, + CancellationToken cancellationToken) { var result = await _omniSharpExtractInterfaceOptionsService.GetExtractInterfaceOptionsAsync(extractableMembers, defaultInterfaceName).ConfigureAwait(false); return new( diff --git a/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenameOptions.cs b/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenameOptions.cs index 647202d6d5bdc..f0fe8155ca5d2 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenameOptions.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenameOptions.cs @@ -11,7 +11,7 @@ internal readonly record struct OmniSharpRenameOptions( bool RenameInStrings, bool RenameOverloads) { - internal RenameOptionSet ToRenameOptions() + internal SymbolRenameOptions ToRenameOptions() => new( RenameOverloads: RenameOverloads, RenameInStrings: RenameInStrings, diff --git a/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs b/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs index d62aced448ddb..e0cc58f5333bf 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs @@ -12,13 +12,18 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp { internal static class OmniSharpRenamer { - public static Task RenameSymbolAsync( + public readonly record struct RenameResult(Solution Solution, string? ErrorMessage); + + public static async Task RenameSymbolAsync( Solution solution, ISymbol symbol, string newName, OmniSharpRenameOptions options, ImmutableHashSet? nonConflictSymbols, CancellationToken cancellationToken) - => Renamer.RenameSymbolAsync(solution, symbol, newName, options.ToRenameOptions(), nonConflictSymbols, cancellationToken); + { + var resolution = await Renamer.RenameSymbolAsync(solution, symbol, newName, options.ToRenameOptions(), nonConflictSymbols, cancellationToken).ConfigureAwait(false); + return new RenameResult(resolution.NewSolution, resolution.ErrorMessage); + } } } diff --git a/src/Tools/ExternalAccess/Razor/IRazorDocumentExcerptService.cs b/src/Tools/ExternalAccess/Razor/IRazorDocumentExcerptService.cs index 0078d5eed3297..fed026d507d1c 100644 --- a/src/Tools/ExternalAccess/Razor/IRazorDocumentExcerptService.cs +++ b/src/Tools/ExternalAccess/Razor/IRazorDocumentExcerptService.cs @@ -2,14 +2,21 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor { + [Obsolete("Use IRazorDocumentExcerptServiceImplementation instead")] internal interface IRazorDocumentExcerptService { Task TryExcerptAsync(Document document, TextSpan span, RazorExcerptMode mode, CancellationToken cancellationToken); } + + internal interface IRazorDocumentExcerptServiceImplementation + { + Task TryExcerptAsync(Document document, TextSpan span, RazorExcerptMode mode, RazorClassificationOptionsWrapper options, CancellationToken cancellationToken); + } } diff --git a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj b/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj index 99384a461d79c..ce33e4cc3781f 100644 --- a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj +++ b/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj @@ -23,6 +23,7 @@ + diff --git a/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs b/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs index 58d6fd5a592ad..164758b6f3031 100644 --- a/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs +++ b/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs @@ -26,7 +26,8 @@ public static bool SupportsFormattingOnTypedCharacter(Document document, char ch { Contract.ThrowIfFalse(document.Project.Language is LanguageNames.CSharp); var formattingService = document.GetRequiredLanguageService(); - return formattingService.SupportsFormattingOnTypedCharacter(document, ch); + var options = AutoFormattingOptions.From(document.Project); + return formattingService.SupportsFormattingOnTypedCharacter(document, options, ch); } /// diff --git a/src/Tools/ExternalAccess/Razor/RazorClassificationOptionsWrapper.cs b/src/Tools/ExternalAccess/Razor/RazorClassificationOptionsWrapper.cs new file mode 100644 index 0000000000000..89452b542d87d --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/RazorClassificationOptionsWrapper.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Classification; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor +{ + internal readonly struct RazorClassificationOptionsWrapper + { + public static RazorClassificationOptionsWrapper Default = new(ClassificationOptions.Default); + + internal readonly ClassificationOptions UnderlyingObject; + + public RazorClassificationOptionsWrapper(ClassificationOptions underlyingObject) + => UnderlyingObject = underlyingObject; + } +} diff --git a/src/Tools/ExternalAccess/Razor/RazorClassifierAccessor.cs b/src/Tools/ExternalAccess/Razor/RazorClassifierAccessor.cs new file mode 100644 index 0000000000000..2a3633e40084d --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/RazorClassifierAccessor.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.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor +{ + internal static class RazorClassifierAccessor + { + public static async Task> GetClassifiedSpansAsync(Document document, TextSpan textSpan, RazorClassificationOptionsWrapper options, CancellationToken cancellationToken) + { + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + return Classifier.GetClassifiedSpans(document.Project.Solution.Workspace.Services, semanticModel, textSpan, options.UnderlyingObject, cancellationToken); + } + } +} diff --git a/src/Tools/ExternalAccess/Razor/RazorDocumentExcerptServiceWrapper.cs b/src/Tools/ExternalAccess/Razor/RazorDocumentExcerptServiceWrapper.cs index f021d9abcc3c2..10dccf7614aa3 100644 --- a/src/Tools/ExternalAccess/Razor/RazorDocumentExcerptServiceWrapper.cs +++ b/src/Tools/ExternalAccess/Razor/RazorDocumentExcerptServiceWrapper.cs @@ -6,19 +6,26 @@ using System.ComponentModel; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor { internal sealed class RazorDocumentExcerptServiceWrapper : IDocumentExcerptService { - private readonly IRazorDocumentExcerptService _razorDocumentExcerptService; + [Obsolete] + private readonly IRazorDocumentExcerptService? _legacyRazorDocumentExcerptService; + private readonly IRazorDocumentExcerptServiceImplementation? _impl; + + [Obsolete] public RazorDocumentExcerptServiceWrapper(IRazorDocumentExcerptService razorDocumentExcerptService) - { - _razorDocumentExcerptService = razorDocumentExcerptService ?? throw new ArgumentNullException(nameof(razorDocumentExcerptService)); - } + => _legacyRazorDocumentExcerptService = razorDocumentExcerptService; + + public RazorDocumentExcerptServiceWrapper(IRazorDocumentExcerptServiceImplementation impl) + => _impl = impl; public async Task TryExcerptAsync(Document document, TextSpan span, ExcerptMode mode, CancellationToken cancellationToken) { @@ -26,17 +33,25 @@ public RazorDocumentExcerptServiceWrapper(IRazorDocumentExcerptService razorDocu { ExcerptMode.SingleLine => RazorExcerptMode.SingleLine, ExcerptMode.Tooltip => RazorExcerptMode.Tooltip, - _ => throw new InvalidEnumArgumentException($"Unsupported enum type {mode}."), + _ => throw ExceptionUtilities.UnexpectedValue(mode), }; - var nullableRazorExcerpt = await _razorDocumentExcerptService.TryExcerptAsync(document, span, razorMode, cancellationToken).ConfigureAwait(false); - if (nullableRazorExcerpt == null) + + RazorExcerptResult? result; + if (_impl != null) + { + var options = ClassificationOptions.From(document.Project); + result = await _impl.TryExcerptAsync(document, span, razorMode, new RazorClassificationOptionsWrapper(options), cancellationToken).ConfigureAwait(false); + } + else { - return null; +#pragma warning disable CS0612 // Type or member is obsolete + Contract.ThrowIfNull(_legacyRazorDocumentExcerptService); + result = await _legacyRazorDocumentExcerptService.TryExcerptAsync(document, span, razorMode, cancellationToken).ConfigureAwait(false); +#pragma warning restore } - var razorExcerpt = nullableRazorExcerpt.Value; - var roslynExcerpt = new ExcerptResult(razorExcerpt.Content, razorExcerpt.MappedSpan, razorExcerpt.ClassifiedSpans, razorExcerpt.Document, razorExcerpt.Span); - return roslynExcerpt; + var razorExcerpt = result.Value; + return new ExcerptResult(razorExcerpt.Content, razorExcerpt.MappedSpan, razorExcerpt.ClassifiedSpans, razorExcerpt.Document, razorExcerpt.Span); } } } diff --git a/src/Tools/ExternalAccess/Razor/RazorDocumentServiceProviderWrapper.cs b/src/Tools/ExternalAccess/Razor/RazorDocumentServiceProviderWrapper.cs index 463a02e623599..b490d3b5c7089 100644 --- a/src/Tools/ExternalAccess/Razor/RazorDocumentServiceProviderWrapper.cs +++ b/src/Tools/ExternalAccess/Razor/RazorDocumentServiceProviderWrapper.cs @@ -50,8 +50,20 @@ public RazorDocumentServiceProviderWrapper(IRazorDocumentServiceProvider innerDo ref _lazyExcerptService, static documentServiceProvider => { - var razorExcerptService = documentServiceProvider.GetService(); - return razorExcerptService is not null ? new RazorDocumentExcerptServiceWrapper(razorExcerptService) : null; + var impl = documentServiceProvider.GetService(); + if (impl != null) + { + return new RazorDocumentExcerptServiceWrapper(impl); + } + +#pragma warning disable CS0612, CS0618 // Type or member is obsolete + var legacyImpl = documentServiceProvider.GetService(); + if (legacyImpl != null) + { + return new RazorDocumentExcerptServiceWrapper(legacyImpl); + } +#pragma warning restore + return null; }, _innerDocumentServiceProvider); diff --git a/src/Tools/IdeBenchmarks/FormatterBenchmarks.cs b/src/Tools/IdeBenchmarks/FormatterBenchmarks.cs index 2c3dc828bdee3..e4640cb7fb4bd 100644 --- a/src/Tools/IdeBenchmarks/FormatterBenchmarks.cs +++ b/src/Tools/IdeBenchmarks/FormatterBenchmarks.cs @@ -8,6 +8,8 @@ using System.Linq; using System.Threading; using BenchmarkDotNet.Attributes; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Test.Utilities; @@ -43,7 +45,9 @@ public object FormatCSharp() using var workspace = TestWorkspace.CreateCSharp(text); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); - return Formatter.GetFormattedTextChanges(document.GetSyntaxRootSynchronously(CancellationToken.None), workspace); + var root = document.GetSyntaxRootSynchronously(CancellationToken.None); + var options = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService().GetFormattingOptions(DictionaryAnalyzerConfigOptions.Empty); + return Formatter.GetFormattedTextChanges(root, workspace.Services, options, CancellationToken.None); } [Benchmark] @@ -54,7 +58,9 @@ public object FormatVisualBasic() using var workspace = TestWorkspace.CreateVisualBasic(text); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); - return Formatter.GetFormattedTextChanges(document.GetSyntaxRootSynchronously(CancellationToken.None), workspace); + var root = document.GetSyntaxRootSynchronously(CancellationToken.None); + var options = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService().GetFormattingOptions(DictionaryAnalyzerConfigOptions.Empty); + return Formatter.GetFormattedTextChanges(root, workspace.Services, options, CancellationToken.None); } } } diff --git a/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj b/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj index dc6edddad635c..40c7da6d63273 100644 --- a/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj +++ b/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj @@ -11,6 +11,7 @@ true 9 + False diff --git a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs index e6e437e549170..b726e411bea9b 100644 --- a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs @@ -10,7 +10,6 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using System.Threading; using System.Threading.Tasks; using AnalyzerRunner; @@ -18,7 +17,7 @@ using BenchmarkDotNet.Diagnosers; using Microsoft.Build.Locator; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.MSBuild; using Microsoft.CodeAnalysis.NavigateTo; @@ -26,7 +25,9 @@ namespace IdeCoreBenchmarks { + // [GcServer(true)] [MemoryDiagnoser] + [SimpleJob(launchCount: 1, warmupCount: 0, targetCount: 0, invocationCount: 1, id: "QuickJob")] public class NavigateToBenchmarks { string _solutionPath; @@ -69,7 +70,7 @@ private async Task LoadSolutionAsync() if (!File.Exists(_solutionPath)) throw new ArgumentException("Couldn't find Roslyn.sln"); - Console.Write("Found Roslyn.sln: " + Process.GetCurrentProcess().Id); + Console.WriteLine("Found Roslyn.sln: " + Process.GetCurrentProcess().Id); var assemblies = MSBuildMefHostServices.DefaultAssemblies .Add(typeof(AnalyzerRunnerHelper).Assembly) .Add(typeof(FindReferencesBenchmarks).Assembly); @@ -112,8 +113,72 @@ public void IterationCleanup() _workspace = null; } + // [Benchmark] + public async Task RunSerialIndexing() + { + Console.WriteLine("start profiling now"); + // Thread.Sleep(10000); + Console.WriteLine("Starting serial indexing"); + var start = DateTime.Now; + foreach (var project in _workspace.CurrentSolution.Projects) + { + foreach (var document in project.Documents) + { + // await WalkTree(document); + await SyntaxTreeIndex.PrecalculateAsync(document, default).ConfigureAwait(false); + } + } + Console.WriteLine("Serial: " + (DateTime.Now - start)); + Console.ReadLine(); + } + + private static async Task WalkTree(Document document) + { + var root = await document.GetSyntaxRootAsync(); + if (root != null) + { + foreach (var child in root.DescendantNodesAndTokensAndSelf()) + { + + } + } + } + [Benchmark] + public async Task RunProjectParallelIndexing() + { + Console.WriteLine("start profiling now"); + // Thread.Sleep(10000); + Console.WriteLine("Starting parallel indexing"); + var start = DateTime.Now; + foreach (var project in _workspace.CurrentSolution.Projects) + { + var tasks = project.Documents.Select(d => Task.Run( + async () => + { + // await WalkTree(d); + await TopLevelSyntaxTreeIndex.PrecalculateAsync(d, default); + })).ToList(); + await Task.WhenAll(tasks); + } + Console.WriteLine("Project parallel: " + (DateTime.Now - start)); + Console.ReadLine(); + } + + // [Benchmark] + public async Task RunFullParallelIndexing() + { + Console.WriteLine("Attach now"); + Console.ReadLine(); + 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(); + await Task.WhenAll(tasks); + Console.WriteLine("Solution parallel: " + (DateTime.Now - start)); + } + // [Benchmark] public async Task RunNavigateTo() { Console.WriteLine("Starting navigate to"); @@ -126,8 +191,8 @@ public async Task RunNavigateTo() var result = await Task.WhenAll(searchTasks).ConfigureAwait(false); var sum = result.Sum(); - //start = DateTime.Now; - Console.WriteLine("Num results: " + (DateTime.Now - start)); + Console.WriteLine("Num results: " + sum); + Console.WriteLine("Time to search: " + (DateTime.Now - start)); } private async Task SearchAsync(Project project, ImmutableArray priorityDocuments) diff --git a/src/Tools/IdeCoreBenchmarks/RenameBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/RenameBenchmarks.cs index 1219912c50abe..b21ed03065935 100644 --- a/src/Tools/IdeCoreBenchmarks/RenameBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/RenameBenchmarks.cs @@ -10,6 +10,7 @@ using BenchmarkDotNet.Attributes; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Rename; namespace IdeCoreBenchmarks { @@ -51,7 +52,7 @@ public void IterationSetup() [Benchmark] public void RenameNodes() { - _ = Microsoft.CodeAnalysis.Rename.Renamer.RenameSymbolAsync(_solution, _symbol, "NewName", optionSet: null); + _ = Renamer.RenameSymbolAsync(_solution, _symbol, new SymbolRenameOptions(), "NewName"); } [IterationCleanup] diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/AbstractFileWriter.cs b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/AbstractFileWriter.cs index 5fec3287b3cfd..ae79b7308004f 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/AbstractFileWriter.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/AbstractFileWriter.cs @@ -385,7 +385,7 @@ protected List GetKindsOfFieldOrNearestParent(TreeType nd, Field field) }).Single(f => f.Name == field.Name); } - return field.Kinds; + return field.Kinds.Distinct().ToList(); } #endregion Node helpers diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Grammar/GrammarGenerator.cs b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Grammar/GrammarGenerator.cs index 1f86270b55cbc..b4499e6de7b00 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Grammar/GrammarGenerator.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Grammar/GrammarGenerator.cs @@ -36,14 +36,35 @@ public static string Run(List types) if (type is Node && type.Children.Count > 0) { // Convert rules like `a: (x | y) ...` into: + // // a: x ... // | y ...; - if (type.Children[0] is Field field && field.Kinds.Count > 0) + // + // Note: if we have `a: (a1 | b1) ... (ax | bx) presume that that's a paired construct and generate: + // + // a: a1 ... ax + // | b1 ... bx; + + if (type.Children.First() is Field firstField && firstField.Kinds.Count > 0) { - foreach (var kind in field.Kinds) + var originalFirstFieldKinds = firstField.Kinds.ToList(); + if (type.Children.Count >= 2 && type.Children.Last() is Field lastField && lastField.Kinds.Count == firstField.Kinds.Count) + { + var originalLastFieldKinds = lastField.Kinds.ToList(); + for (int i = 0; i < originalFirstFieldKinds.Count; i++) + { + firstField.Kinds = new List { originalFirstFieldKinds[i] }; + lastField.Kinds = new List { originalLastFieldKinds[i] }; + rules[type.Name].Add(HandleChildren(type.Children)); + } + } + else { - field.Kinds = new List { kind }; - rules[type.Name].Add(HandleChildren(type.Children)); + for (int i = 0; i < originalFirstFieldKinds.Count; i++) + { + firstField.Kinds = new List { originalFirstFieldKinds[i] }; + rules[type.Name].Add(HandleChildren(type.Children)); + } } } else diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Model/Kind.cs b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Model/Kind.cs index dd5b7720129ae..ccc852b750c90 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Model/Kind.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Model/Kind.cs @@ -2,22 +2,23 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - +using System; using System.Xml.Serialization; namespace CSharpSyntaxGenerator { - public class Kind + public class Kind : IEquatable { [XmlAttribute] - public string Name; + public string? Name; + + public override bool Equals(object? obj) + => Equals(obj as Kind); - public override bool Equals(object obj) - => obj is Kind kind && - Name == kind.Name; + public bool Equals(Kind? other) + => Name == other?.Name; public override int GetHashCode() - => Name.GetHashCode(); + => Name == null ? 0 : Name.GetHashCode(); } } diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/SourceWriter.cs b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/SourceWriter.cs index cf91de6d75f54..720b6397e21d5 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/SourceWriter.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/SourceWriter.cs @@ -633,9 +633,10 @@ private void WriteGreenFactory(Node nd, bool withSyntaxFactoryContext = false) { WriteLine("switch (kind)"); OpenBlock(); - foreach (var kind in nd.Kinds) + var kinds = nd.Kinds.Distinct().ToList(); + foreach (var kind in kinds) { - WriteLine($"case SyntaxKind.{kind.Name}:{(kind == nd.Kinds.Last() ? " break;" : "")}"); + WriteLine($"case SyntaxKind.{kind.Name}:{(kind == kinds.Last() ? " break;" : "")}"); } WriteLine("default: throw new ArgumentException(nameof(kind));"); CloseBlock(); @@ -667,7 +668,7 @@ private void WriteGreenFactory(Node nd, bool withSyntaxFactoryContext = false) { WriteLine($"switch ({pname}.Kind)"); OpenBlock(); - var kinds = field.Kinds.ToList(); + var kinds = field.Kinds.Distinct().ToList(); //we need to check for Kind=None as well as node == null because that's what the red factory will pass if (IsOptional(field)) @@ -1540,9 +1541,10 @@ private void WriteRedFactory(Node nd) { WriteLine("switch (kind)"); OpenBlock(); - foreach (var kind in nd.Kinds) + var kinds = nd.Kinds.Distinct().ToList(); + foreach (var kind in kinds) { - WriteLine($"case SyntaxKind.{kind.Name}:{(kind == nd.Kinds.Last() ? " break;" : "")}"); + WriteLine($"case SyntaxKind.{kind.Name}:{(kind == kinds.Last() ? " break;" : "")}"); } WriteLine("default: throw new ArgumentException(nameof(kind));"); CloseBlock(); diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/IOperationGenerator/IOperationClassWriter.cs b/src/Tools/Source/CompilerGeneratorTools/Source/IOperationGenerator/IOperationClassWriter.cs index a894d43850f08..db5a8a02e5ddb 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/IOperationGenerator/IOperationClassWriter.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/IOperationGenerator/IOperationClassWriter.cs @@ -451,6 +451,7 @@ void writeClass(AbstractNode type) if (node != null) { + writeCountProperty(publicIOperationProps); if (!node.SkipChildrenGeneration) { writeEnumeratorMethods(type, publicIOperationProps, node); @@ -652,6 +653,44 @@ string getKind(AbstractNode node) return GetSubName(node.Name); } + void writeCountProperty(List publicIOperationProps) + { + Write("internal override int ChildOperationsCount =>"); + if (publicIOperationProps.Count == 0) + { + WriteLine(" 0;"); + } + else + { + WriteLine(""); + Indent(); + bool isFirst = true; + foreach (var prop in publicIOperationProps) + { + if (isFirst) + { + isFirst = false; + } + else + { + WriteLine(" +"); + } + + if (IsImmutableArray(prop.Type, out _)) + { + Write($"{prop.Name}.Length"); + } + else + { + Write($"({prop.Name} is null ? 0 : 1)"); + } + } + + WriteLine(";"); + Outdent(); + } + } + void writeEnumeratorMethods(AbstractNode type, List publicIOperationProps, Node node) { if (publicIOperationProps.Count > 0) @@ -674,7 +713,20 @@ void writeEnumeratorMethods(AbstractNode type, List publicIOperationPr } } - WriteLine("protected override IOperation GetCurrent(int slot, int index)"); + writeGetCurrent(orderedProperties); + writeMoveNext(orderedProperties); + writeMoveNextReversed(orderedProperties); + } + else + { + WriteLine("internal override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index));"); + WriteLine("internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue);"); + WriteLine("internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue);"); + } + + void writeGetCurrent(List orderedProperties) + { + WriteLine("internal override IOperation GetCurrent(int slot, int index)"); Indent(); WriteLine("=> slot switch"); Brace(); @@ -705,8 +757,11 @@ void writeEnumeratorMethods(AbstractNode type, List publicIOperationPr Outdent(); WriteLine("};"); Outdent(); + } - WriteLine("protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex)"); + void writeMoveNext(List orderedProperties) + { + WriteLine("internal override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex)"); Brace(); WriteLine("switch (previousSlot)"); Brace(); @@ -714,7 +769,7 @@ void writeEnumeratorMethods(AbstractNode type, List publicIOperationPr int slot = 0; for (; slot < orderedProperties.Count; slot++) { - // Operation.Enumerator starts indexes at -1. For a given property, the general psuedocode is: + // Operation.ChildCollection.Enumerator starts indexes at -1. For a given property, the general pseudocode is: // case previousSlot: // if (element i is valid) return (true, i, 0); @@ -779,10 +834,80 @@ void writeEnumeratorMethods(AbstractNode type, List publicIOperationPr Unbrace(); Unbrace(); } - else + + void writeMoveNextReversed(List orderedProperties) { - WriteLine("protected override IOperation GetCurrent(int slot, int index) => throw ExceptionUtilities.UnexpectedValue((slot, index));"); - WriteLine("protected override (bool hasNext, int nextSlot, int nextIndex) MoveNext(int previousSlot, int previousIndex) => (false, int.MinValue, int.MinValue);"); + WriteLine("internal override (bool hasNext, int nextSlot, int nextIndex) MoveNextReversed(int previousSlot, int previousIndex)"); + Brace(); + WriteLine("switch (previousSlot)"); + Brace(); + + int slot = orderedProperties.Count - 1; + for (; slot >= 0; slot--) + { + // Operation.ChildCollection.Reversed.Enumerator starts indexes at int.MaxValue. For a given property, the general pseudocode is: + + // case previousSlot: + // if (element i is valid) return (true, i, 0); + // else goto i; + + // If i is an IOperation, is valid means not null. If i is an ImmutableArray, it means not empty. + // As IOperation is fully nullable-enabled, and the abstract `Current` method is nullable, we'll + // get a warning if it attempts to return a null IOperation from such an array, so we don't need + // to have explicit Debug.Assert code for this. + + // Then, if the property is an immutable array: + // case i when previousIndex > 0: + // return (true, i, previousIndex - 1); + + // While the next index is still valid, this will hit this case for i, only moving to the next + // element (meaning i - 1) after the array is exhausted. + + var previousSlot = slot == (orderedProperties.Count - 1) ? "int.MaxValue" : (slot + 1).ToString(); + var prop = orderedProperties[slot]; + + WriteLine($"case {previousSlot}:"); + Indent(); + + bool isImmutableArray = IsImmutableArray(prop.Type, out _); + if (isImmutableArray) + { + WriteLine($"if (!{prop.Name}.IsEmpty) return (true, {slot}, {prop.Name}.Length - 1);"); + } + else + { + WriteLine($"if ({prop.Name} != null) return (true, {slot}, 0);"); + } + + WriteLine($"else goto case {slot};"); + + Outdent(); + + if (isImmutableArray) + { + WriteLine($"case {slot} when previousIndex > 0:"); + Indent(); + WriteLine($"return (true, {slot}, previousIndex - 1);"); + Outdent(); + } + } + + // We introduce an explicit "eof" slot, that indicates the enumerator has moved beyond + // the end of the sequence. This allows us to differentiate between repeated calls to + // MoveNext, which are valid and always return false and the "eof" slot, and invalid + // usage of the API (which may give us a slot that we are not expecting.) + WriteLine("case 0:"); + WriteLine("case -1:"); + Indent(); + WriteLine($"return (false, -1, 0);"); + Outdent(); + + WriteLine("default:"); + Indent(); + WriteLine("throw ExceptionUtilities.UnexpectedValue((previousSlot, previousIndex));"); + Outdent(); + Unbrace(); + Unbrace(); } } } diff --git a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx index 258958fa8a8b1..40a3b3131603e 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx +++ b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx @@ -524,6 +524,9 @@ Prefer 'is null' for reference equality checks 'is null' is a C# string and should not be localized. + + Prefer parameter null checking + Report invalid placeholders in 'string.Format' calls diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.CodeModelEventCollector.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.CodeModelEventCollector.cs index 023065d7f6ee9..bffa78eec4eda 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.CodeModelEventCollector.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.CodeModelEventCollector.cs @@ -30,7 +30,7 @@ public CodeModelEventCollector(AbstractCodeModelService codeModelService) { } - private IReadOnlyList GetValidMembers(SyntaxNode node) + private static IReadOnlyList GetValidMembers(SyntaxNode node) { return CSharpCodeModelService .GetChildMemberNodes(node) @@ -708,10 +708,10 @@ private bool CompareBaseLists(BaseTypeDeclarationSyntax oldType, BaseTypeDeclara return false; } - private bool CompareModifiers(MemberDeclarationSyntax oldMember, MemberDeclarationSyntax newMember) + private static bool CompareModifiers(MemberDeclarationSyntax oldMember, MemberDeclarationSyntax newMember) => oldMember.GetModifierFlags() == newMember.GetModifierFlags(); - private bool CompareModifiers(ParameterSyntax oldParameter, ParameterSyntax newParameter) + private static bool CompareModifiers(ParameterSyntax oldParameter, ParameterSyntax newParameter) => oldParameter.GetParameterFlags() == newParameter.GetParameterFlags(); private bool CompareNames(NameSyntax oldName, NameSyntax newName) @@ -826,7 +826,7 @@ private bool CompareTypes(TypeSyntax oldType, TypeSyntax newType) return false; } - private TypeSyntax GetReturnType(BaseMethodDeclarationSyntax method) + private static TypeSyntax GetReturnType(BaseMethodDeclarationSyntax method) { if (method is MethodDeclarationSyntax methodDecl) { @@ -968,7 +968,7 @@ protected override void EnqueueRemoveEvent(SyntaxNode node, SyntaxNode parent, C } } - private void AddEventToEventQueueForAttributes(AttributeSyntax attribute, SyntaxNode parent, Action enqueueAddOrRemoveEvent) + private static void AddEventToEventQueueForAttributes(AttributeSyntax attribute, SyntaxNode parent, Action enqueueAddOrRemoveEvent) { if (parent is BaseFieldDeclarationSyntax baseField) { diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs index 809c4f25f3db2..43766199f0f01 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs @@ -132,7 +132,7 @@ private class NodeLocator : AbstractNodeLocator } } - private VirtualTreePoint GetBodyStartPoint(SourceText text, SyntaxToken openBrace) + private static VirtualTreePoint GetBodyStartPoint(SourceText text, SyntaxToken openBrace) { Debug.Assert(!openBrace.IsMissing); @@ -208,7 +208,7 @@ private VirtualTreePoint GetBodyStartPoint(SourceText text, OptionSet options, S } } - private VirtualTreePoint GetBodyEndPoint(SourceText text, SyntaxToken closeBrace) + private static VirtualTreePoint GetBodyEndPoint(SourceText text, SyntaxToken closeBrace) { var closeBraceLine = text.Lines.GetLineFromPosition(closeBrace.SpanStart); var textBeforeBrace = text.ToString(TextSpan.FromBounds(closeBraceLine.Start, closeBrace.SpanStart)); @@ -218,7 +218,7 @@ private VirtualTreePoint GetBodyEndPoint(SourceText text, SyntaxToken closeBrace : new VirtualTreePoint(closeBrace.SyntaxTree, text, closeBrace.SpanStart); } - private VirtualTreePoint GetStartPoint(SourceText text, ArrowExpressionClauseSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, ArrowExpressionClauseSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -239,7 +239,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, ArrowExpressionClauseSyn return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetStartPoint(SourceText text, AttributeSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, AttributeSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -272,7 +272,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, AttributeSyntax node, En return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetStartPoint(SourceText text, AttributeArgumentSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, AttributeArgumentSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -302,7 +302,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, AttributeArgumentSyntax return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetStartPoint(SourceText text, BaseTypeDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, BaseTypeDeclarationSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -429,7 +429,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, OptionSet options, BaseM return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private AccessorDeclarationSyntax FindFirstAccessorNode(BasePropertyDeclarationSyntax node) + private static AccessorDeclarationSyntax FindFirstAccessorNode(BasePropertyDeclarationSyntax node) { if (node.AccessorList == null) { @@ -553,7 +553,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, OptionSet options, Acces return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetStartPoint(SourceText text, BaseNamespaceDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, BaseNamespaceDeclarationSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -602,7 +602,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, BaseNamespaceDeclaration return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetStartPoint(SourceText text, DelegateDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, DelegateDeclarationSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -642,7 +642,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, DelegateDeclarationSynta return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetStartPoint(SourceText text, UsingDirectiveSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, UsingDirectiveSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -675,7 +675,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, UsingDirectiveSyntax nod return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetStartPoint(SourceText text, VariableDeclaratorSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, VariableDeclaratorSyntax node, EnvDTE.vsCMPart part) { var field = node.FirstAncestorOrSelf(); int startPosition; @@ -716,7 +716,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, VariableDeclaratorSyntax return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetStartPoint(SourceText text, EnumMemberDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, EnumMemberDeclarationSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -756,7 +756,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, EnumMemberDeclarationSyn return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetStartPoint(SourceText text, ParameterSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetStartPoint(SourceText text, ParameterSyntax node, EnvDTE.vsCMPart part) { int startPosition; @@ -796,7 +796,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, ParameterSyntax node, En return new VirtualTreePoint(node.SyntaxTree, text, startPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, ArrowExpressionClauseSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, ArrowExpressionClauseSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -814,7 +814,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, ArrowExpressionClauseSynta return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, AttributeSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, AttributeSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -847,7 +847,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, AttributeSyntax node, EnvD return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, AttributeArgumentSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, AttributeArgumentSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -877,7 +877,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, AttributeArgumentSyntax no return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, BaseTypeDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, BaseTypeDeclarationSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -918,7 +918,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, BaseTypeDeclarationSyntax return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, BaseMethodDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, BaseMethodDeclarationSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -992,7 +992,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, BaseMethodDeclarationSynta return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, BasePropertyDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, BasePropertyDeclarationSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -1052,7 +1052,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, BasePropertyDeclarationSyn return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, AccessorDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, AccessorDeclarationSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -1091,7 +1091,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, AccessorDeclarationSyntax return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, DelegateDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, DelegateDeclarationSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -1132,7 +1132,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, DelegateDeclarationSyntax return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, BaseNamespaceDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, BaseNamespaceDeclarationSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -1181,7 +1181,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, BaseNamespaceDeclarationSy return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, UsingDirectiveSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, UsingDirectiveSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -1214,7 +1214,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, UsingDirectiveSyntax node, return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, EnumMemberDeclarationSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, EnumMemberDeclarationSyntax node, EnvDTE.vsCMPart part) { int endPosition; @@ -1255,7 +1255,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, EnumMemberDeclarationSynta return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, VariableDeclaratorSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, VariableDeclaratorSyntax node, EnvDTE.vsCMPart part) { var field = node.FirstAncestorOrSelf(); int endPosition; @@ -1297,7 +1297,7 @@ private VirtualTreePoint GetEndPoint(SourceText text, VariableDeclaratorSyntax n return new VirtualTreePoint(node.SyntaxTree, text, endPosition); } - private VirtualTreePoint GetEndPoint(SourceText text, ParameterSyntax node, EnvDTE.vsCMPart part) + private static VirtualTreePoint GetEndPoint(SourceText text, ParameterSyntax node, EnvDTE.vsCMPart part) { int endPosition; diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs index b0f363c319fce..be9bb321c62a7 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs @@ -1221,7 +1221,7 @@ public override SyntaxNode SetAccess(SyntaxNode node, EnvDTE.vsCMAccess newAcces return member.UpdateModifiers(modifierFlags); } - private IList CollectComments(IList triviaList) + private static IList CollectComments(IList triviaList) { var commentList = new List(); @@ -2766,7 +2766,7 @@ private Document Delete(Document document, VariableDeclaratorSyntax node) } } - private Document Delete(Document document, EnumMemberDeclarationSyntax node) + private static Document Delete(Document document, EnumMemberDeclarationSyntax node) { var enumDeclaration = (EnumDeclarationSyntax)node.Parent!; var members = enumDeclaration.Members; @@ -2786,7 +2786,7 @@ private Document Delete(Document document, EnumMemberDeclarationSyntax node) return document.ReplaceNodeSynchronously(enumDeclaration, newEnumDeclaration, CancellationToken.None); } - private Document Delete(Document document, AttributeSyntax node) + private static Document Delete(Document document, AttributeSyntax node) { var attributeList = node.FirstAncestorOrSelf(); Contract.ThrowIfNull(attributeList); @@ -2813,7 +2813,7 @@ private Document Delete(Document document, AttributeSyntax node) } } - private Document Delete(Document document, AttributeArgumentSyntax node) + private static Document Delete(Document document, AttributeArgumentSyntax node) { var argumentList = node.FirstAncestorOrSelf(); Contract.ThrowIfNull(argumentList); @@ -2823,7 +2823,7 @@ private Document Delete(Document document, AttributeArgumentSyntax node) return document.ReplaceNodeSynchronously(argumentList, newArgumentList, CancellationToken.None); } - private Document Delete(Document document, ParameterSyntax node) + private static Document Delete(Document document, ParameterSyntax node) { var parameterList = node.FirstAncestorOrSelf(); Contract.ThrowIfNull(parameterList); @@ -2833,7 +2833,7 @@ private Document Delete(Document document, ParameterSyntax node) return document.ReplaceNodeSynchronously(parameterList, newParameterList, CancellationToken.None); } - private Document DeleteMember(Document document, SyntaxNode node) + private static Document DeleteMember(Document document, SyntaxNode node) { var text = document.GetTextSynchronously(CancellationToken.None); @@ -3279,7 +3279,7 @@ private static MemberDeclarationSyntax GetMember(SyntaxNode container, int index throw Exceptions.ThrowEFail(); } - private SyntaxNode EnsureAfterEndRegion(int index, SyntaxNode container) + private static SyntaxNode EnsureAfterEndRegion(int index, SyntaxNode container) { // If the next token after our member has only whitespace and #endregion as leading // trivia, we'll move that to be leading trivia of our member. diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/EndRegionFormattingRule.cs b/src/VisualStudio/CSharp/Impl/CodeModel/EndRegionFormattingRule.cs index 189e902661ebb..07a3f3dd02c44 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/EndRegionFormattingRule.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/EndRegionFormattingRule.cs @@ -18,7 +18,7 @@ private EndRegionFormattingRule() { } - private bool IsAfterEndRegionBeforeMethodDeclaration(SyntaxToken previousToken) + private static bool IsAfterEndRegionBeforeMethodDeclaration(SyntaxToken previousToken) { if (previousToken.Kind() == SyntaxKind.EndOfDirectiveToken) { diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs index 1e726b9de6f24..598ced9a8dc29 100644 --- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; @@ -103,6 +103,10 @@ private IEnumerable GetNullCheckingCodeStyleOptions(AnalyzerCo description: CSharpVSResources.Prefer_null_check_over_type_check, editorConfigOptions: editorConfigOptions, visualStudioOptions: visualStudioOptions, updater: updaterService, fileName: FileName); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferParameterNullChecking, + description: CSharpVSResources.Prefer_parameter_null_checking, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService, fileName: FileName); } private IEnumerable GetModifierCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) @@ -132,6 +136,10 @@ private IEnumerable GetCodeBlockCodeStyleOptions(AnalyzerConfi valueDescriptions: new[] { CSharpVSResources.Block_scoped, CSharpVSResources.File_scoped }, editorConfigOptions: editorConfigOptions, visualStudioOptions: visualStudioOptions, updater: updaterService, fileName: FileName); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferMethodGroupConversion, + description: ServicesVSResources.Prefer_method_group_conversion, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService, fileName: FileName); } private IEnumerable GetExpressionCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodeCleanupFixer.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodeCleanupFixer.cs index d1f083ab35c0b..07fc6cd967c95 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodeCleanupFixer.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodeCleanupFixer.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeCleanup; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.Shell; @@ -16,12 +17,12 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService { [Export(typeof(AbstractCodeCleanUpFixer))] [ContentType(ContentTypeNames.CSharpContentType)] - internal class CSharpCodeCleanUpFixer : AbstractCodeCleanUpFixer + internal sealed class CSharpCodeCleanUpFixer : AbstractCodeCleanUpFixer { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpCodeCleanUpFixer(IThreadingContext threadingContext, VisualStudioWorkspaceImpl workspace, IVsHierarchyItemManager vsHierarchyItemManager) - : base(threadingContext, workspace, vsHierarchyItemManager) + public CSharpCodeCleanUpFixer(IThreadingContext threadingContext, VisualStudioWorkspaceImpl workspace, IVsHierarchyItemManager vsHierarchyItemManager, IGlobalOptionService globalOptions) + : base(threadingContext, workspace, vsHierarchyItemManager, globalOptions) { } } diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCreateServicesOnTextViewConnection.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCreateServicesOnTextViewConnection.cs index 6dd428dec410a..011df352c3f73 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCreateServicesOnTextViewConnection.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCreateServicesOnTextViewConnection.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService; @@ -36,9 +37,10 @@ internal class CSharpCreateServicesOnTextViewConnection : AbstractCreateServices [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpCreateServicesOnTextViewConnection( VisualStudioWorkspace workspace, + IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider, IThreadingContext threadingContext) - : base(workspace, listenerProvider, threadingContext, LanguageNames.CSharp) + : base(workspace, globalOptions, listenerProvider, threadingContext, LanguageNames.CSharp) { } @@ -53,7 +55,7 @@ protected override void OnSolutionRemoved() protected override Task InitializeServiceForOpenedDocumentAsync(Document document) { // Only pre-populate cache if import completion is enabled - if (this.Workspace.Options.GetOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp) != true) + if (GlobalOptions.GetOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp) != true) return Task.CompletedTask; lock (_gate) diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs index d25bf87376217..cd41dbd6a4432 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs @@ -2,11 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Immutable; using System.Composition; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -14,6 +13,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServices; @@ -33,52 +33,34 @@ public CSharpHelpContextService() { } - public override string Language - { - get - { - return "csharp"; - } - } - - public override string Product - { - get - { - return "csharp"; - } - } + public override string Language => "csharp"; + public override string Product => "csharp"; private static string Keyword(string text) => text + "_CSharpKeyword"; public override async Task GetHelpTermAsync(Document document, TextSpan span, CancellationToken cancellationToken) { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - - var syntaxFacts = document.GetLanguageService(); - // For now, find the token under the start of the selection. - var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var token = await syntaxTree.GetTouchingTokenAsync(span.Start, cancellationToken, findInsideTrivia: true).ConfigureAwait(false); - if (IsValid(token, span)) + if (token.Span.IntersectsWith(span)) { var semanticModel = await document.ReuseExistingSpeculativeModelAsync(span, cancellationToken).ConfigureAwait(false); - var result = TryGetText(token, semanticModel, document, syntaxFacts, cancellationToken); + var result = TryGetText(token, semanticModel, document, cancellationToken); if (string.IsNullOrEmpty(result)) { var previousToken = token.GetPreviousToken(); - if (IsValid(previousToken, span)) - { - result = TryGetText(previousToken, semanticModel, document, syntaxFacts, cancellationToken); - } + if (previousToken.Span.IntersectsWith(span)) + result = TryGetText(previousToken, semanticModel, document, cancellationToken); } return result; } + var root = await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); var trivia = root.FindTrivia(span.Start, findInsideTrivia: true); if (trivia.Span.IntersectsWith(span) && trivia.Kind() == SyntaxKind.PreprocessingMessageTrivia && trivia.Token.GetAncestor() != null) @@ -93,15 +75,12 @@ public override async Task GetHelpTermAsync(Document document, TextSpan var start = span.Start; var end = span.Start; + var syntaxFacts = document.GetRequiredLanguageService(); while (start > 0 && syntaxFacts.IsIdentifierPartCharacter(text[start - 1])) - { start--; - } while (end < text.Length - 1 && syntaxFacts.IsIdentifierPartCharacter(text[end])) - { end++; - } return text.GetSubText(TextSpan.FromBounds(start, end)).ToString(); } @@ -109,19 +88,13 @@ public override async Task GetHelpTermAsync(Document document, TextSpan return string.Empty; } - private static bool IsValid(SyntaxToken token, TextSpan span) - { - // If the token doesn't actually intersect with our position, give up - return token.Kind() == SyntaxKind.EndIfDirectiveTrivia || token.Span.IntersectsWith(span); - } - - private string TryGetText(SyntaxToken token, SemanticModel semanticModel, Document document, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken) + private string TryGetText(SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken) { if (TryGetTextForSpecialCharacters(token, out var text) || TryGetTextForContextualKeyword(token, out text) || - TryGetTextForCombinationKeyword(token, syntaxFacts, out text) || + TryGetTextForCombinationKeyword(token, out text) || TryGetTextForKeyword(token, out text) || - TryGetTextForPreProcessor(token, syntaxFacts, out text) || + TryGetTextForPreProcessor(token, out text) || TryGetTextForOperator(token, document, out text) || TryGetTextForSymbol(token, semanticModel, document, cancellationToken, out text)) { @@ -131,25 +104,28 @@ private string TryGetText(SyntaxToken token, SemanticModel semanticModel, Docume return string.Empty; } - private bool TryGetTextForSpecialCharacters(SyntaxToken token, out string text) + private static bool TryGetTextForSpecialCharacters(SyntaxToken token, [NotNullWhen(true)] out string? text) { if (token.IsKind(SyntaxKind.InterpolatedStringStartToken) || token.IsKind(SyntaxKind.InterpolatedStringEndToken) || - token.IsKind(SyntaxKind.InterpolatedStringTextToken)) + token.IsKind(SyntaxKind.InterpolatedRawStringEndToken) || + token.IsKind(SyntaxKind.InterpolatedStringTextToken) || + token.IsKind(SyntaxKind.InterpolatedSingleLineRawStringStartToken) || + token.IsKind(SyntaxKind.InterpolatedMultiLineRawStringStartToken)) { - text = "$_CSharpKeyword"; + text = Keyword("$"); return true; } if (token.IsVerbatimStringLiteral()) { - text = "@_CSharpKeyword"; + text = Keyword("@"); return true; } if (token.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken)) { - text = "@$_CSharpKeyword"; + text = Keyword("@$"); return true; } @@ -157,13 +133,16 @@ private bool TryGetTextForSpecialCharacters(SyntaxToken token, out string text) return false; } - private bool TryGetTextForSymbol(SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken, out string text) + private bool TryGetTextForSymbol( + SyntaxToken token, SemanticModel semanticModel, Document document, CancellationToken cancellationToken, + [NotNullWhen(true)] out string? text) { - ISymbol symbol; + ISymbol? symbol = null; if (token.Parent is TypeArgumentListSyntax) { var genericName = token.GetAncestor(); - symbol = semanticModel.GetSymbolInfo(genericName, cancellationToken).Symbol ?? semanticModel.GetTypeInfo(genericName, cancellationToken).Type; + if (genericName != null) + symbol = semanticModel.GetSymbolInfo(genericName, cancellationToken).Symbol ?? semanticModel.GetTypeInfo(genericName, cancellationToken).Type; } else if (token.Parent is NullableTypeSyntax && token.IsKind(SyntaxKind.QuestionToken)) { @@ -177,7 +156,7 @@ private bool TryGetTextForSymbol(SyntaxToken token, SemanticModel semanticModel, if (symbol == null) { - var bindableParent = document.GetLanguageService().TryGetBindableParent(token); + var bindableParent = document.GetRequiredLanguageService().TryGetBindableParent(token); var overloads = bindableParent != null ? semanticModel.GetMemberGroup(bindableParent) : ImmutableArray.Empty; symbol = overloads.FirstOrDefault(); } @@ -192,7 +171,7 @@ private bool TryGetTextForSymbol(SyntaxToken token, SemanticModel semanticModel, // Range variable: use the type if (symbol is IRangeVariableSymbol) { - var info = semanticModel.GetTypeInfo(token.Parent, cancellationToken); + var info = semanticModel.GetTypeInfo(token.GetRequiredParent(), cancellationToken); symbol = info.Type; } @@ -203,11 +182,17 @@ private bool TryGetTextForSymbol(SyntaxToken token, SemanticModel semanticModel, return false; } - text = symbol != null ? FormatSymbol(symbol) : null; - return symbol != null; + if (symbol is IDiscardSymbol) + { + text = Keyword("discard"); + return true; + } + + text = FormatSymbol(symbol); + return text != null; } - private static bool TryGetTextForOperator(SyntaxToken token, Document document, out string text) + private static bool TryGetTextForOperator(SyntaxToken token, Document document, [NotNullWhen(true)] out string? text) { if (token.IsKind(SyntaxKind.ExclamationToken) && token.Parent.IsKind(SyntaxKind.SuppressNullableWarningExpression)) @@ -223,7 +208,7 @@ private static bool TryGetTextForOperator(SyntaxToken token, Document document, return false; } - var syntaxFacts = document.GetLanguageService(); + var syntaxFacts = document.GetRequiredLanguageService(); if (syntaxFacts.IsOperator(token) || syntaxFacts.IsPredefinedOperator(token) || SyntaxFacts.IsAssignmentExpressionOperatorToken(token.Kind())) { text = Keyword(syntaxFacts.GetText(token.RawKind)); @@ -232,25 +217,25 @@ private static bool TryGetTextForOperator(SyntaxToken token, Document document, if (token.IsKind(SyntaxKind.ColonColonToken)) { - text = "::_CSharpKeyword"; + text = Keyword("::"); return true; } if (token.IsKind(SyntaxKind.ColonToken) && token.Parent is NameColonSyntax) { - text = "namedParameter_CSharpKeyword"; + text = Keyword("namedParameter"); return true; } if (token.IsKind(SyntaxKind.QuestionToken) && token.Parent is ConditionalExpressionSyntax) { - text = "?_CSharpKeyword"; + text = Keyword("?"); return true; } if (token.IsKind(SyntaxKind.EqualsGreaterThanToken)) { - text = "=>_CSharpKeyword"; + text = Keyword("=>"); return true; } @@ -258,8 +243,10 @@ private static bool TryGetTextForOperator(SyntaxToken token, Document document, return false; } - private static bool TryGetTextForPreProcessor(SyntaxToken token, ISyntaxFactsService syntaxFacts, out string text) + private static bool TryGetTextForPreProcessor(SyntaxToken token, [NotNullWhen(true)] out string? text) { + var syntaxFacts = CSharpSyntaxFacts.Instance; + if (syntaxFacts.IsPreprocessorKeyword(token)) { text = "#" + token.Text; @@ -276,7 +263,7 @@ private static bool TryGetTextForPreProcessor(SyntaxToken token, ISyntaxFactsSer return false; } - private static bool TryGetTextForContextualKeyword(SyntaxToken token, out string text) + private static bool TryGetTextForContextualKeyword(SyntaxToken token, [NotNullWhen(true)] out string? text) { if (token.Text == "nameof") { @@ -303,14 +290,9 @@ private static bool TryGetTextForContextualKeyword(SyntaxToken token, out string break; case SyntaxKind.WhereKeyword: - if (token.Parent.GetAncestorOrThis() != null) - { - text = "whereconstraint_CSharpKeyword"; - } - else - { - text = "whereclause_CSharpKeyword"; - } + text = token.Parent.GetAncestorOrThis() != null + ? "whereconstraint_CSharpKeyword" + : "whereclause_CSharpKeyword"; return true; } @@ -319,17 +301,17 @@ private static bool TryGetTextForContextualKeyword(SyntaxToken token, out string text = null; return false; } - private static bool TryGetTextForCombinationKeyword(SyntaxToken token, ISyntaxFactsService syntaxFacts, out string text) + private static bool TryGetTextForCombinationKeyword(SyntaxToken token, [NotNullWhen(true)] out string? text) { switch (token.Kind()) { - case SyntaxKind.PrivateKeyword when ModifiersContains(token, syntaxFacts, SyntaxKind.ProtectedKeyword): - case SyntaxKind.ProtectedKeyword when ModifiersContains(token, syntaxFacts, SyntaxKind.PrivateKeyword): + case SyntaxKind.PrivateKeyword when ModifiersContains(token, SyntaxKind.ProtectedKeyword): + case SyntaxKind.ProtectedKeyword when ModifiersContains(token, SyntaxKind.PrivateKeyword): text = "privateprotected_CSharpKeyword"; return true; - case SyntaxKind.ProtectedKeyword when ModifiersContains(token, syntaxFacts, SyntaxKind.InternalKeyword): - case SyntaxKind.InternalKeyword when ModifiersContains(token, syntaxFacts, SyntaxKind.ProtectedKeyword): + case SyntaxKind.ProtectedKeyword when ModifiersContains(token, SyntaxKind.InternalKeyword): + case SyntaxKind.InternalKeyword when ModifiersContains(token, SyntaxKind.ProtectedKeyword): text = "protectedinternal_CSharpKeyword"; return true; @@ -346,13 +328,13 @@ private static bool TryGetTextForCombinationKeyword(SyntaxToken token, ISyntaxFa text = null; return false; - static bool ModifiersContains(SyntaxToken token, ISyntaxFactsService syntaxFacts, SyntaxKind kind) + static bool ModifiersContains(SyntaxToken token, SyntaxKind kind) { - return syntaxFacts.GetModifiers(token.Parent).Any(t => t.IsKind(kind)); + return CSharpSyntaxFacts.Instance.GetModifiers(token.Parent).Any(t => t.IsKind(kind)); } } - private static bool TryGetTextForKeyword(SyntaxToken token, out string text) + private static bool TryGetTextForKeyword(SyntaxToken token, [NotNullWhen(true)] out string? text) { if (token.IsKind(SyntaxKind.InKeyword)) { @@ -400,7 +382,7 @@ private static bool TryGetTextForKeyword(SyntaxToken token, out string text) } if (token.ValueText == "var" && token.IsKind(SyntaxKind.IdentifierToken) && - token.Parent.Parent is VariableDeclarationSyntax declaration && token.Parent == declaration.Type) + token.Parent?.Parent is VariableDeclarationSyntax declaration && token.Parent == declaration.Type) { text = "var_CSharpKeyword"; return true; @@ -433,8 +415,11 @@ private static string FormatNamespaceOrTypeSymbol(INamespaceOrTypeSymbol symbol) return displayString; } - public override string FormatSymbol(ISymbol symbol) + public override string? FormatSymbol(ISymbol? symbol) { + if (symbol == null) + return null; + if (symbol is ITypeSymbol or INamespaceSymbol) { return FormatNamespaceOrTypeSymbol((INamespaceOrTypeSymbol)symbol); diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml index 2c1019da82c54..45a1797761567 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml @@ -15,17 +15,14 @@ - + + + + + + + + diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index 8481b60ff48ad..016306b63d84c 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -4,6 +4,7 @@ #nullable disable +using System; using System.Windows; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Classification; @@ -17,9 +18,10 @@ using Microsoft.CodeAnalysis.Editor.InlineHints; using Microsoft.CodeAnalysis.Editor.Options; using Microsoft.CodeAnalysis.Editor.Shared.Options; -using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Fading; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; +using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; using Microsoft.CodeAnalysis.ImplementType; using Microsoft.CodeAnalysis.InlineHints; using Microsoft.CodeAnalysis.QuickInfo; @@ -46,9 +48,7 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon InitializeComponent(); - BindToOption(Background_analysis_scope_active_file, SolutionCrawlerOptions.BackgroundAnalysisScopeOption, BackgroundAnalysisScope.ActiveFile, LanguageNames.CSharp); - BindToOption(Background_analysis_scope_open_files, SolutionCrawlerOptions.BackgroundAnalysisScopeOption, BackgroundAnalysisScope.OpenFilesAndProjects, LanguageNames.CSharp); - BindToOption(Background_analysis_scope_full_solution, SolutionCrawlerOptions.BackgroundAnalysisScopeOption, BackgroundAnalysisScope.FullSolution, LanguageNames.CSharp); + BindToOption(Run_background_code_analysis_for, SolutionCrawlerOptions.BackgroundAnalysisScopeOption, LanguageNames.CSharp); BindToOption(DisplayDiagnosticsInline, InlineDiagnosticsOptions.EnableInlineDiagnostics, LanguageNames.CSharp); BindToOption(at_the_end_of_the_line_of_code, InlineDiagnosticsOptions.Location, InlineDiagnosticsLocations.PlacedAtEndOfCode, LanguageNames.CSharp); BindToOption(on_the_right_edge_of_the_editor_window, InlineDiagnosticsOptions.Location, InlineDiagnosticsLocations.PlacedAtEndOfEditor, LanguageNames.CSharp); @@ -65,8 +65,8 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon BindToOption(PlaceSystemNamespaceFirst, GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp); BindToOption(SeparateImportGroups, GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.CSharp); - BindToOption(SuggestForTypesInReferenceAssemblies, SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.CSharp); - BindToOption(SuggestForTypesInNuGetPackages, SymbolSearchOptions.SuggestForTypesInNuGetPackages, LanguageNames.CSharp); + BindToOption(SuggestForTypesInReferenceAssemblies, SymbolSearchOptionsStorage.SearchReferenceAssemblies, LanguageNames.CSharp); + BindToOption(SuggestForTypesInNuGetPackages, SymbolSearchOptionsStorage.SearchNuGetPackages, LanguageNames.CSharp); BindToOption(AddUsingsOnPaste, FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.CSharp, () => { // This option used to be backed by an experimentation flag but is no longer. @@ -83,8 +83,8 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon BindToOption(Show_outlining_for_comments_and_preprocessor_regions, BlockStructureOptions.Metadata.ShowOutliningForCommentsAndPreprocessorRegions, LanguageNames.CSharp); BindToOption(Collapse_regions_when_collapsing_to_definitions, BlockStructureOptions.Metadata.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp); - BindToOption(Fade_out_unused_usings, FadingOptions.FadeOutUnusedImports, LanguageNames.CSharp); - BindToOption(Fade_out_unreachable_code, FadingOptions.FadeOutUnreachableCode, LanguageNames.CSharp); + BindToOption(Fade_out_unused_usings, FadingOptions.Metadata.FadeOutUnusedImports, LanguageNames.CSharp); + BindToOption(Fade_out_unreachable_code, FadingOptions.Metadata.FadeOutUnreachableCode, LanguageNames.CSharp); BindToOption(Show_guides_for_declaration_level_constructs, BlockStructureOptions.Metadata.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp); BindToOption(Show_guides_for_code_level_constructs, BlockStructureOptions.Metadata.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp); @@ -128,8 +128,12 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon BindToOption(Colorize_regular_expressions, ClassificationOptions.Metadata.ColorizeRegexPatterns, LanguageNames.CSharp); BindToOption(Report_invalid_regular_expressions, RegularExpressionsOptions.ReportInvalidRegexPatterns, LanguageNames.CSharp); - BindToOption(Highlight_related_components_under_cursor, RegularExpressionsOptions.HighlightRelatedRegexComponentsUnderCursor, LanguageNames.CSharp); - BindToOption(Show_completion_list, CompletionOptions.Metadata.ProvideRegexCompletions, LanguageNames.CSharp); + BindToOption(Highlight_related_regular_expression_components_under_cursor, RegularExpressionsOptions.HighlightRelatedRegexComponentsUnderCursor, LanguageNames.CSharp); + BindToOption(Show_completion_list, CompletionOptionsStorage.ProvideRegexCompletions, LanguageNames.CSharp); + + BindToOption(Colorize_JSON_strings, ClassificationOptions.Metadata.ColorizeJsonPatterns, LanguageNames.CSharp); + BindToOption(Report_invalid_JSON_strings, JsonFeatureOptions.ReportInvalidJsonPatterns, LanguageNames.CSharp); + BindToOption(Highlight_related_JSON_components_under_cursor, JsonFeatureOptions.HighlightRelatedJsonComponentsUnderCursor, LanguageNames.CSharp); BindToOption(Editor_color_scheme, ColorSchemeOptions.ColorScheme); @@ -154,7 +158,7 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon BindToOption(ShowInheritanceMargin, FeatureOnOffOptions.ShowInheritanceMargin, LanguageNames.CSharp, () => true); BindToOption(InheritanceMarginCombinedWithIndicatorMargin, FeatureOnOffOptions.InheritanceMarginCombinedWithIndicatorMargin); - BindToOption(AutomaticallyOpenStackTraceExplorer, StackTraceExplorerOptions.OpenOnFocus); + BindToOption(AutomaticallyOpenStackTraceExplorer, StackTraceExplorerOptionsMetadata.OpenOnFocus); } // Since this dialog is constructed once for the lifetime of the application and VS Theme can be changed after the application has started, @@ -179,8 +183,6 @@ private void UpdatePullDiagnosticsOptions() var normalPullDiagnosticsOption = OptionStore.GetOption(InternalDiagnosticsOptions.NormalDiagnosticMode); Enable_pull_diagnostics_experimental_requires_restart.IsChecked = GetCheckboxValueForDiagnosticMode(normalPullDiagnosticsOption); - Enable_Razor_pull_diagnostics_experimental_requires_restart.IsChecked = OptionStore.GetOption(InternalDiagnosticsOptions.RazorDiagnosticMode) == DiagnosticMode.Pull; - static bool? GetCheckboxValueForDiagnosticMode(DiagnosticMode mode) { return mode switch @@ -228,18 +230,6 @@ private void Enable_pull_diagnostics_experimental_requires_restart_Indeterminate UpdatePullDiagnosticsOptions(); } - private void Enable_Razor_pull_diagnostics_experimental_requires_restart_Checked(object sender, RoutedEventArgs e) - { - this.OptionStore.SetOption(InternalDiagnosticsOptions.RazorDiagnosticMode, DiagnosticMode.Pull); - UpdatePullDiagnosticsOptions(); - } - - private void Enable_Razor_pull_diagnostics_experimental_requires_restart_Unchecked(object sender, RoutedEventArgs e) - { - this.OptionStore.SetOption(InternalDiagnosticsOptions.RazorDiagnosticMode, DiagnosticMode.Push); - UpdatePullDiagnosticsOptions(); - } - private void UpdateInlineHintsOptions() { var enabledForParameters = this.OptionStore.GetOption(InlineParameterHintsOptions.Metadata.EnabledForParameters, LanguageNames.CSharp); diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs index 90285b616fb77..a2c8199f320d2 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.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. -#nullable disable - using Microsoft.CodeAnalysis.Editor.ColorSchemes; +using Microsoft.CodeAnalysis.SolutionCrawler; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options { @@ -13,18 +12,33 @@ internal static class AdvancedOptionPageStrings public static string Option_Analysis => ServicesVSResources.Analysis; - public static string Option_Background_analysis_scope - => ServicesVSResources.Background_analysis_scope_colon; + public static string Option_Run_background_code_analysis_for + => ServicesVSResources.Run_background_code_analysis_for_colon; + + public static string Option_Background_Analysis_Scope_None + => ServicesVSResources.None; public static string Option_Background_Analysis_Scope_Active_File => ServicesVSResources.Current_document; - public static string Option_Background_Analysis_Scope_Open_Files_And_Projects + public static string Option_Background_Analysis_Scope_Open_Files => ServicesVSResources.Open_documents; public static string Option_Background_Analysis_Scope_Full_Solution => ServicesVSResources.Entire_solution; + public static BackgroundAnalysisScope Option_Background_Analysis_Scope_None_Tag + => BackgroundAnalysisScope.None; + + public static BackgroundAnalysisScope Option_Background_Analysis_Scope_Active_File_Tag + => BackgroundAnalysisScope.ActiveFile; + + public static BackgroundAnalysisScope Option_Background_Analysis_Scope_Open_Files_Tag + => BackgroundAnalysisScope.OpenFiles; + + public static BackgroundAnalysisScope Option_Background_Analysis_Scope_Full_Solution_Tag + => BackgroundAnalysisScope.FullSolution; + public static string Option_Enable_navigation_to_decompiled_sources => ServicesVSResources.Enable_navigation_to_decompiled_sources; @@ -107,14 +121,10 @@ public static string Option_EditorHelp => CSharpVSResources.Editor_Help; public static string Option_EnableHighlightKeywords - { - get { return CSharpVSResources.Highlight_related_keywords_under_cursor; } - } + => CSharpVSResources.Highlight_related_keywords_under_cursor; public static string Option_EnableHighlightReferences - { - get { return CSharpVSResources.Highlight_references_to_symbol_under_cursor; } - } + => CSharpVSResources.Highlight_references_to_symbol_under_cursor; public static string Option_EnterOutliningMode => CSharpVSResources.Enter_outlining_mode_when_files_open; @@ -297,6 +307,15 @@ public static string Show_inheritance_margin public static string Combine_inheritance_margin_with_indicator_margin => ServicesVSResources.Combine_inheritance_margin_with_indicator_margin; + public static string Option_JSON_strings => + ServicesVSResources.JSON_strings; + + public static string Option_Colorize_JSON_strings => + ServicesVSResources.Colorize_JSON_strings; + + public static string Option_Report_invalid_JSON_strings => + ServicesVSResources.Report_invalid_JSON_strings; + public static string Inheritance_Margin => ServicesVSResources.Inheritance_Margin; diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.BraceCompletion.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.BraceCompletion.cs index e9f83e5bcb7d6..4e2bea903475a 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.BraceCompletion.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.BraceCompletion.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.BraceCompletion; +using Microsoft.CodeAnalysis.Formatting; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options { @@ -10,8 +10,8 @@ public partial class AutomationObject { public int Formatting_TriggerOnBlockCompletion { - get { return GetBooleanOption(BraceCompletionOptions.AutoFormattingOnCloseBrace); } - set { SetBooleanOption(BraceCompletionOptions.AutoFormattingOnCloseBrace, value); } + get { return GetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace); } + set { SetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, value); } } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Completion.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Completion.cs index ebeda2a4e0516..cd83affc78f4c 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Completion.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Completion.cs @@ -10,8 +10,8 @@ public partial class AutomationObject { public int BringUpOnIdentifier { - get { return GetBooleanOption(CompletionOptions.Metadata.TriggerOnTypingLetters); } - set { SetBooleanOption(CompletionOptions.Metadata.TriggerOnTypingLetters, value); } + get { return GetBooleanOption(CompletionOptionsStorage.TriggerOnTypingLetters); } + set { SetBooleanOption(CompletionOptionsStorage.TriggerOnTypingLetters, value); } } public int HighlightMatchingPortionsOfCompletionListItems @@ -28,32 +28,32 @@ public int ShowCompletionItemFilters public int ShowItemsFromUnimportedNamespaces { - get { return GetBooleanOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces); } - set { SetBooleanOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, value); } + get { return GetBooleanOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces); } + set { SetBooleanOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, value); } } public int InsertNewlineOnEnterWithWholeWord { - get { return (int)GetOption(CompletionOptions.Metadata.EnterKeyBehavior); } - set { SetOption(CompletionOptions.Metadata.EnterKeyBehavior, (EnterKeyRule)value); } + get { return (int)GetOption(CompletionOptionsStorage.EnterKeyBehavior); } + set { SetOption(CompletionOptionsStorage.EnterKeyBehavior, (EnterKeyRule)value); } } public int EnterKeyBehavior { - get { return (int)GetOption(CompletionOptions.Metadata.EnterKeyBehavior); } - set { SetOption(CompletionOptions.Metadata.EnterKeyBehavior, (EnterKeyRule)value); } + get { return (int)GetOption(CompletionOptionsStorage.EnterKeyBehavior); } + set { SetOption(CompletionOptionsStorage.EnterKeyBehavior, (EnterKeyRule)value); } } public int SnippetsBehavior { - get { return (int)GetOption(CompletionOptions.Metadata.SnippetsBehavior); } - set { SetOption(CompletionOptions.Metadata.SnippetsBehavior, (SnippetsRule)value); } + get { return (int)GetOption(CompletionOptionsStorage.SnippetsBehavior); } + set { SetOption(CompletionOptionsStorage.SnippetsBehavior, (SnippetsRule)value); } } public int TriggerInArgumentLists { - get { return GetBooleanOption(CompletionOptions.Metadata.TriggerInArgumentLists); } - set { SetBooleanOption(CompletionOptions.Metadata.TriggerInArgumentLists, value); } + get { return GetBooleanOption(CompletionOptionsStorage.TriggerInArgumentLists); } + set { SetBooleanOption(CompletionOptionsStorage.TriggerInArgumentLists, value); } } public int EnableArgumentCompletionSnippets diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Fading.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Fading.cs index 2f36c973be2b1..59d8f174cf6aa 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Fading.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Fading.cs @@ -10,14 +10,14 @@ public partial class AutomationObject { public int Fading_FadeOutUnreachableCode { - get { return GetBooleanOption(FadingOptions.FadeOutUnreachableCode); } - set { SetBooleanOption(FadingOptions.FadeOutUnreachableCode, value); } + get { return GetBooleanOption(FadingOptions.Metadata.FadeOutUnreachableCode); } + set { SetBooleanOption(FadingOptions.Metadata.FadeOutUnreachableCode, value); } } public int Fading_FadeOutUnusedImports { - get { return GetBooleanOption(FadingOptions.FadeOutUnusedImports); } - set { SetBooleanOption(FadingOptions.FadeOutUnusedImports, value); } + get { return GetBooleanOption(FadingOptions.Metadata.FadeOutUnusedImports); } + set { SetBooleanOption(FadingOptions.Metadata.FadeOutUnusedImports, value); } } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs index 6b8e468419bb7..d03626adf6e21 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Formatting.cs @@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Editor.Implementation.Formatting; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options { @@ -305,20 +306,20 @@ public int Wrapping_PreserveSingleLine public int Formatting_TriggerOnPaste { - get { return GetBooleanOption(FormattingBehaviorOptions.FormatOnPaste); } - set { SetBooleanOption(FormattingBehaviorOptions.FormatOnPaste, value); } + get { return GetBooleanOption(FormattingOptionsMetadata.FormatOnPaste); } + set { SetBooleanOption(FormattingOptionsMetadata.FormatOnPaste, value); } } public int Formatting_TriggerOnStatementCompletion { - get { return GetBooleanOption(FormattingBehaviorOptions.AutoFormattingOnSemicolon); } - set { SetBooleanOption(FormattingBehaviorOptions.AutoFormattingOnSemicolon, value); } + get { return GetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnSemicolon); } + set { SetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnSemicolon, value); } } public int AutoFormattingOnTyping { - get { return GetBooleanOption(FormattingBehaviorOptions.AutoFormattingOnTyping); } - set { SetBooleanOption(FormattingBehaviorOptions.AutoFormattingOnTyping, value); } + get { return GetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnTyping); } + set { SetBooleanOption(AutoFormattingOptions.Metadata.AutoFormattingOnTyping, value); } } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.ObsoleteAndUnused.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.ObsoleteAndUnused.cs index 0b198abcb2dff..ca2b77091a87c 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.ObsoleteAndUnused.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.ObsoleteAndUnused.cs @@ -47,7 +47,7 @@ public int ShowSnippets { get { - return GetOption(CompletionOptions.Metadata.SnippetsBehavior) == SnippetsRule.AlwaysInclude + return GetOption(CompletionOptionsStorage.SnippetsBehavior) == SnippetsRule.AlwaysInclude ? 1 : 0; } @@ -55,11 +55,11 @@ public int ShowSnippets { if (value == 0) { - SetOption(CompletionOptions.Metadata.SnippetsBehavior, SnippetsRule.NeverInclude); + SetOption(CompletionOptionsStorage.SnippetsBehavior, SnippetsRule.NeverInclude); } else { - SetOption(CompletionOptions.Metadata.SnippetsBehavior, SnippetsRule.AlwaysInclude); + SetOption(CompletionOptionsStorage.SnippetsBehavior, SnippetsRule.AlwaysInclude); } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Style.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Style.cs index e8f977663d36b..527c4b7de2e52 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Style.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Style.cs @@ -69,6 +69,12 @@ public string Style_PreferCoalesceExpression set { SetXmlOption(CodeStyleOptions2.PreferCoalesceExpression, value); } } + public string Style_PreferMethodGroupConversion + { + get { return GetXmlOption(CSharpCodeStyleOptions.PreferMethodGroupConversion); } + set { SetXmlOption(CSharpCodeStyleOptions.PreferMethodGroupConversion, value); } + } + public string Style_PreferNullPropagation { get { return GetXmlOption(CodeStyleOptions2.PreferNullPropagation); } @@ -237,6 +243,12 @@ public string Style_PreferIsNullCheckOverReferenceEqualityMethod set { SetXmlOption(CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, value); } } + public string Style_PreferParameterNullChecking + { + get { return GetXmlOption(CSharpCodeStyleOptions.PreferParameterNullChecking); } + set { SetXmlOption(CSharpCodeStyleOptions.PreferParameterNullChecking, value); } + } + public string Style_PreferNullCheckOverTypeCheck { get { return GetXmlOption(CSharpCodeStyleOptions.PreferNullCheckOverTypeCheck); } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.SymbolSearch.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.SymbolSearch.cs index bce969be1174f..f566f959f1019 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.SymbolSearch.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.SymbolSearch.cs @@ -10,14 +10,14 @@ public partial class AutomationObject { public int AddImport_SuggestForTypesInReferenceAssemblies { - get { return GetBooleanOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies); } - set { SetBooleanOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, value); } + get { return GetBooleanOption(SymbolSearchOptionsStorage.SearchReferenceAssemblies); } + set { SetBooleanOption(SymbolSearchOptionsStorage.SearchReferenceAssemblies, value); } } public int AddImport_SuggestForTypesInNuGetPackages { - get { return GetBooleanOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages); } - set { SetBooleanOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages, value); } + get { return GetBooleanOption(SymbolSearchOptionsStorage.SearchNuGetPackages); } + set { SetBooleanOption(SymbolSearchOptionsStorage.SearchNuGetPackages, value); } } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/FormattingOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/FormattingOptionPageControl.xaml.cs index ee490088aed98..dad354fd0f866 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/FormattingOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/FormattingOptionPageControl.xaml.cs @@ -5,7 +5,7 @@ #nullable disable using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.BraceCompletion; +using Microsoft.CodeAnalysis.Editor.Implementation.Formatting; using Microsoft.CodeAnalysis.Formatting; using Microsoft.VisualStudio.LanguageServices.Implementation.Options; using System.Runtime.CompilerServices; @@ -33,11 +33,11 @@ public FormattingOptionPageControl(OptionStore optionStore) : base(optionStore) FormatOnReturnCheckBox.Content = CSharpVSResources.Automatically_format_on_return; FormatOnPasteCheckBox.Content = CSharpVSResources.Automatically_format_on_paste; - BindToOption(FormatWhenTypingCheckBox, FormattingBehaviorOptions.AutoFormattingOnTyping, LanguageNames.CSharp); - BindToOption(FormatOnCloseBraceCheckBox, BraceCompletionOptions.AutoFormattingOnCloseBrace, LanguageNames.CSharp); - BindToOption(FormatOnSemicolonCheckBox, FormattingBehaviorOptions.AutoFormattingOnSemicolon, LanguageNames.CSharp); - BindToOption(FormatOnReturnCheckBox, FormattingBehaviorOptions.AutoFormattingOnReturn, LanguageNames.CSharp); - BindToOption(FormatOnPasteCheckBox, FormattingBehaviorOptions.FormatOnPaste, LanguageNames.CSharp); + BindToOption(FormatWhenTypingCheckBox, AutoFormattingOptions.Metadata.AutoFormattingOnTyping, LanguageNames.CSharp); + BindToOption(FormatOnCloseBraceCheckBox, AutoFormattingOptions.Metadata.AutoFormattingOnCloseBrace, LanguageNames.CSharp); + BindToOption(FormatOnSemicolonCheckBox, AutoFormattingOptions.Metadata.AutoFormattingOnSemicolon, LanguageNames.CSharp); + BindToOption(FormatOnReturnCheckBox, AutoFormattingOptions.Metadata.AutoFormattingOnReturn, LanguageNames.CSharp); + BindToOption(FormatOnPasteCheckBox, FormattingOptionsMetadata.FormatOnPaste, LanguageNames.CSharp); } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/IndentationViewModel.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/IndentationViewModel.cs index e02ad6364f116..6f9603c58e202 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/IndentationViewModel.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/IndentationViewModel.cs @@ -87,9 +87,9 @@ public IndentationViewModel(OptionStore optionStore, IServiceProvider servicePro Items.Add(new TextBlock() { Text = CSharpVSResources.Label_Indentation }); - Items.Add(new RadioButtonViewModel(CSharpVSResources.Place_goto_labels_in_leftmost_column, GotoLabelPreview, "goto", LabelPositionOptions.LeftMost, CSharpFormattingOptions.LabelPositioning, this, optionStore)); - Items.Add(new RadioButtonViewModel(CSharpVSResources.Indent_labels_normally, GotoLabelPreview, "goto", LabelPositionOptions.NoIndent, CSharpFormattingOptions.LabelPositioning, this, optionStore)); - Items.Add(new RadioButtonViewModel(CSharpVSResources.Place_goto_labels_one_indent_less_than_current, GotoLabelPreview, "goto", LabelPositionOptions.OneLess, CSharpFormattingOptions.LabelPositioning, this, optionStore)); + Items.Add(new RadioButtonViewModel(CSharpVSResources.Place_goto_labels_in_leftmost_column, GotoLabelPreview, "goto", LabelPositionOptions.LeftMost, CSharpFormattingOptions2.LabelPositioning, this, optionStore)); + Items.Add(new RadioButtonViewModel(CSharpVSResources.Indent_labels_normally, GotoLabelPreview, "goto", LabelPositionOptions.NoIndent, CSharpFormattingOptions2.LabelPositioning, this, optionStore)); + Items.Add(new RadioButtonViewModel(CSharpVSResources.Place_goto_labels_one_indent_less_than_current, GotoLabelPreview, "goto", LabelPositionOptions.OneLess, CSharpFormattingOptions2.LabelPositioning, this, optionStore)); } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/SpacingViewModel.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/SpacingViewModel.cs index b802b0931e8ca..05f4e673eb482 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/SpacingViewModel.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/SpacingViewModel.cs @@ -144,9 +144,9 @@ public SpacingViewModel(OptionStore optionStore, IServiceProvider serviceProvide Items.Add(new HeaderItemViewModel() { Header = CSharpVSResources.Set_spacing_for_operators }); - Items.Add(new RadioButtonViewModel(CSharpVSResources.Ignore_spaces_around_binary_operators, s_expressionSpacingPreview, "binary", BinaryOperatorSpacingOptions.Ignore, CSharpFormattingOptions.SpacingAroundBinaryOperator, this, OptionStore)); - Items.Add(new RadioButtonViewModel(CSharpVSResources.Remove_spaces_before_and_after_binary_operators, s_expressionSpacingPreview, "binary", BinaryOperatorSpacingOptions.Remove, CSharpFormattingOptions.SpacingAroundBinaryOperator, this, OptionStore)); - Items.Add(new RadioButtonViewModel(CSharpVSResources.Insert_space_before_and_after_binary_operators, s_expressionSpacingPreview, "binary", BinaryOperatorSpacingOptions.Single, CSharpFormattingOptions.SpacingAroundBinaryOperator, this, OptionStore)); + Items.Add(new RadioButtonViewModel(CSharpVSResources.Ignore_spaces_around_binary_operators, s_expressionSpacingPreview, "binary", BinaryOperatorSpacingOptions.Ignore, CSharpFormattingOptions2.SpacingAroundBinaryOperator, this, OptionStore)); + Items.Add(new RadioButtonViewModel(CSharpVSResources.Remove_spaces_before_and_after_binary_operators, s_expressionSpacingPreview, "binary", BinaryOperatorSpacingOptions.Remove, CSharpFormattingOptions2.SpacingAroundBinaryOperator, this, OptionStore)); + Items.Add(new RadioButtonViewModel(CSharpVSResources.Insert_space_before_and_after_binary_operators, s_expressionSpacingPreview, "binary", BinaryOperatorSpacingOptions.Single, CSharpFormattingOptions2.SpacingAroundBinaryOperator, this, OptionStore)); } } } diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs index d2fbb60139c4b..5e5b3643a1901 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; using System.Windows.Data; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.VisualStudio.LanguageServices.Implementation.Options; @@ -958,6 +958,32 @@ public override int GetHashCode() }} //] }} +"; + + private static readonly string s_preferMethodGroupConversion = $@" +using System; + +class Customer1 +{{ + public void M() + {{ +//[ + // {ServicesVSResources.Prefer_colon} + Action writeObject = Console.Write; +//] + }} +}} +class Customer2 +{{ + public void M() + {{ +//[ + // {ServicesVSResources.Over_colon} + Action writeObject = obj => Console.Write(obj); +//] + }} +//] +}} "; private static readonly string s_preferLocalFunctionOverAnonymousFunction = $@" @@ -1122,6 +1148,28 @@ void M2(string value1, string value2) //] }} }} +"; + + private static readonly string s_preferParameterNullChecking = $@" +using System; + +class Customer +{{ +//[ + // {ServicesVSResources.Prefer_colon} + void M1(string value!!) + {{ + }} +//] +//[ + // {ServicesVSResources.Over_colon} + void M2(string value) + {{ + if (value is null) + throw new ArgumentNullException(nameof(value)); + }} +//] +}} "; private static readonly string s_preferNullcheckOverTypeCheck = $@" @@ -2066,6 +2114,7 @@ internal StyleViewModel(OptionStore optionStore, IServiceProvider serviceProvide CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferAutoProperties, ServicesVSResources.analyzer_Prefer_auto_properties, s_preferAutoProperties, s_preferAutoProperties, this, optionStore, codeBlockPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferSimpleUsingStatement, ServicesVSResources.Prefer_simple_using_statement, s_preferSimpleUsingStatement, s_preferSimpleUsingStatement, this, optionStore, codeBlockPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferSystemHashCode, ServicesVSResources.Prefer_System_HashCode_in_GetHashCode, s_preferSystemHashCode, s_preferSystemHashCode, this, optionStore, codeBlockPreferencesGroupTitle)); + CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferMethodGroupConversion, ServicesVSResources.Prefer_method_group_conversion, s_preferMethodGroupConversion, s_preferMethodGroupConversion, this, optionStore, codeBlockPreferencesGroupTitle)); AddParenthesesOptions(OptionStore); @@ -2089,15 +2138,15 @@ internal StyleViewModel(OptionStore optionStore, IServiceProvider serviceProvide CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferTupleSwap, ServicesVSResources.Prefer_tuple_swap, s_preferTupleSwap, s_preferTupleSwap, this, optionStore, expressionPreferencesGroupTitle)); + AddExpressionBodyOptions(optionStore, expressionPreferencesGroupTitle); + AddUnusedValueOptions(optionStore, expressionPreferencesGroupTitle); + // Pattern matching CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferPatternMatching, CSharpVSResources.Prefer_pattern_matching, s_preferPatternMatching, s_preferPatternMatching, this, optionStore, patternMatchingPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck, CSharpVSResources.Prefer_pattern_matching_over_is_with_cast_check, s_preferPatternMatchingOverIsWithCastCheck, s_preferPatternMatchingOverIsWithCastCheck, this, optionStore, patternMatchingPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferPatternMatchingOverAsWithNullCheck, CSharpVSResources.Prefer_pattern_matching_over_as_with_null_check, s_preferPatternMatchingOverAsWithNullCheck, s_preferPatternMatchingOverAsWithNullCheck, this, optionStore, patternMatchingPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferNotPattern, CSharpVSResources.Prefer_pattern_matching_over_mixed_type_check, s_preferPatternMatchingOverMixedTypeCheck, s_preferPatternMatchingOverMixedTypeCheck, this, optionStore, patternMatchingPreferencesGroupTitle)); - AddExpressionBodyOptions(optionStore, expressionPreferencesGroupTitle); - AddUnusedValueOptions(optionStore, expressionPreferencesGroupTitle); - // Variable preferences CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferInlinedVariableDeclaration, ServicesVSResources.Prefer_inlined_variable_declaration, s_preferInlinedVariableDeclaration, s_preferInlinedVariableDeclaration, this, optionStore, variablePreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferDeconstructedVariableDeclaration, ServicesVSResources.Prefer_deconstructed_variable_declaration, s_preferDeconstructedVariableDeclaration, s_preferDeconstructedVariableDeclaration, this, optionStore, variablePreferencesGroupTitle)); @@ -2108,6 +2157,7 @@ internal StyleViewModel(OptionStore optionStore, IServiceProvider serviceProvide CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferCoalesceExpression, ServicesVSResources.Prefer_coalesce_expression, s_preferCoalesceExpression, s_preferCoalesceExpression, this, optionStore, nullCheckingGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferNullPropagation, ServicesVSResources.Prefer_null_propagation, s_preferNullPropagation, s_preferNullPropagation, this, optionStore, nullCheckingGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, CSharpVSResources.Prefer_is_null_for_reference_equality_checks, s_preferIsNullOverReferenceEquals, s_preferIsNullOverReferenceEquals, this, optionStore, nullCheckingGroupTitle)); + CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferParameterNullChecking, CSharpVSResources.Prefer_parameter_null_checking, s_preferParameterNullChecking, s_preferParameterNullChecking, this, optionStore, nullCheckingGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferNullCheckOverTypeCheck, CSharpVSResources.Prefer_null_check_over_type_check, s_preferNullcheckOverTypeCheck, s_preferNullcheckOverTypeCheck, this, optionStore, nullCheckingGroupTitle)); // Using directive preferences. diff --git a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml.cs index e7f2acd5f9bbd..3f668ff9d7f82 100644 --- a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml.cs @@ -23,22 +23,22 @@ public IntelliSenseOptionPageControl(OptionStore optionStore) : base(optionStore BindToOption(Show_completion_item_filters, CompletionViewOptions.ShowCompletionItemFilters, LanguageNames.CSharp); BindToOption(Highlight_matching_portions_of_completion_list_items, CompletionViewOptions.HighlightMatchingPortionsOfCompletionListItems, LanguageNames.CSharp); - BindToOption(Show_completion_list_after_a_character_is_typed, CompletionOptions.Metadata.TriggerOnTypingLetters, LanguageNames.CSharp); - Show_completion_list_after_a_character_is_deleted.IsChecked = this.OptionStore.GetOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp) == true; + 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; - BindToOption(Never_include_snippets, CompletionOptions.Metadata.SnippetsBehavior, SnippetsRule.NeverInclude, LanguageNames.CSharp); - BindToOption(Always_include_snippets, CompletionOptions.Metadata.SnippetsBehavior, SnippetsRule.AlwaysInclude, LanguageNames.CSharp); - BindToOption(Include_snippets_when_question_Tab_is_typed_after_an_identifier, CompletionOptions.Metadata.SnippetsBehavior, SnippetsRule.IncludeAfterTypingIdentifierQuestionTab, LanguageNames.CSharp); + BindToOption(Never_include_snippets, CompletionOptionsStorage.SnippetsBehavior, SnippetsRule.NeverInclude, LanguageNames.CSharp); + BindToOption(Always_include_snippets, CompletionOptionsStorage.SnippetsBehavior, SnippetsRule.AlwaysInclude, LanguageNames.CSharp); + BindToOption(Include_snippets_when_question_Tab_is_typed_after_an_identifier, CompletionOptionsStorage.SnippetsBehavior, SnippetsRule.IncludeAfterTypingIdentifierQuestionTab, LanguageNames.CSharp); - BindToOption(Never_add_new_line_on_enter, CompletionOptions.Metadata.EnterKeyBehavior, EnterKeyRule.Never, LanguageNames.CSharp); - BindToOption(Only_add_new_line_on_enter_with_whole_word, CompletionOptions.Metadata.EnterKeyBehavior, EnterKeyRule.AfterFullyTypedWord, LanguageNames.CSharp); - BindToOption(Always_add_new_line_on_enter, CompletionOptions.Metadata.EnterKeyBehavior, EnterKeyRule.Always, LanguageNames.CSharp); + BindToOption(Never_add_new_line_on_enter, CompletionOptionsStorage.EnterKeyBehavior, EnterKeyRule.Never, LanguageNames.CSharp); + BindToOption(Only_add_new_line_on_enter_with_whole_word, CompletionOptionsStorage.EnterKeyBehavior, EnterKeyRule.AfterFullyTypedWord, LanguageNames.CSharp); + BindToOption(Always_add_new_line_on_enter, CompletionOptionsStorage.EnterKeyBehavior, EnterKeyRule.Always, LanguageNames.CSharp); - BindToOption(Show_name_suggestions, CompletionOptions.Metadata.ShowNameSuggestions, LanguageNames.CSharp); - BindToOption(Automatically_show_completion_list_in_argument_lists, CompletionOptions.Metadata.TriggerInArgumentLists, LanguageNames.CSharp); + BindToOption(Show_name_suggestions, CompletionOptionsStorage.ShowNameSuggestions, LanguageNames.CSharp); + BindToOption(Automatically_show_completion_list_in_argument_lists, CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp); - Show_items_from_unimported_namespaces.IsChecked = this.OptionStore.GetOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp); + Show_items_from_unimported_namespaces.IsChecked = this.OptionStore.GetOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp); Tab_twice_to_insert_arguments.IsChecked = this.OptionStore.GetOption(CompletionViewOptions.EnableArgumentCompletionSnippets, LanguageNames.CSharp); } @@ -54,15 +54,15 @@ private void Show_completion_list_after_a_character_is_typed_Unchecked(object se } private void Show_completion_list_after_a_character_is_deleted_Checked(object sender, RoutedEventArgs e) - => this.OptionStore.SetOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, value: true); + => this.OptionStore.SetOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, value: true); private void Show_completion_list_after_a_character_is_deleted_Unchecked(object sender, RoutedEventArgs e) - => this.OptionStore.SetOption(CompletionOptions.Metadata.TriggerOnDeletion, LanguageNames.CSharp, value: false); + => this.OptionStore.SetOption(CompletionOptionsStorage.TriggerOnDeletion, LanguageNames.CSharp, value: false); private void Show_items_from_unimported_namespaces_CheckedChanged(object sender, RoutedEventArgs e) { Show_items_from_unimported_namespaces.IsThreeState = false; - this.OptionStore.SetOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, value: Show_items_from_unimported_namespaces.IsChecked); + this.OptionStore.SetOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, value: Show_items_from_unimported_namespaces.IsChecked); } private void Tab_twice_to_insert_arguments_CheckedChanged(object sender, RoutedEventArgs e) diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs index c0167f2d5d4e2..c3032d346bcee 100644 --- a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs +++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/TempPECompilerService.cs @@ -67,7 +67,7 @@ public int CompileTempPE(string pszOutputFileName, int sourceCount, string[] fil return result.Success ? VSConstants.S_OK : VSConstants.S_FALSE; } - private CSharpCommandLineArguments ParseCommandLineArguments(string baseDirectory, string[] optionNames, object[] optionValues) + private static CSharpCommandLineArguments ParseCommandLineArguments(string baseDirectory, string[] optionNames, object[] optionValues) { Contract.ThrowIfFalse(optionNames.Length == optionValues.Length); diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs index d9437a82a9a0e..769da32ea385b 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/SnippetCommandHandler.cs @@ -13,10 +13,11 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.Editor.CSharp.CompleteStatement; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Editor; @@ -36,6 +37,7 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets [Name("CSharp Snippets")] [Order(After = PredefinedCompletionNames.CompletionCommandHandler)] [Order(After = Microsoft.CodeAnalysis.Editor.PredefinedCommandHandlerNames.SignatureHelpAfterCompletion)] + [Order(Before = nameof(CompleteStatementCommandHandler))] [Order(Before = Microsoft.CodeAnalysis.Editor.PredefinedCommandHandlerNames.AutomaticLineEnder)] internal sealed class SnippetCommandHandler : AbstractSnippetCommandHandler, diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs index 675d19e7d3f99..d875e7e6382b4 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Xml.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; @@ -23,7 +23,6 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.Editor; -using Microsoft.VisualStudio.LanguageServices.CSharp.Snippets.SnippetFunctions; using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -88,34 +87,8 @@ public SnippetExpansionClient( protected override string FallbackDefaultLiteral => "default"; - public override int GetExpansionFunction(IXMLDOMNode xmlFunctionNode, string bstrFieldName, out IVsExpansionFunction? pFunc) - { - if (!TryGetSnippetFunctionInfo(xmlFunctionNode, out var snippetFunctionName, out var param)) - { - pFunc = null; - return VSConstants.E_INVALIDARG; - } - - switch (snippetFunctionName) - { - case "SimpleTypeName": - pFunc = new SnippetFunctionSimpleTypeName(this, SubjectBuffer, bstrFieldName, param); - return VSConstants.S_OK; - case "ClassName": - pFunc = new SnippetFunctionClassName(this, SubjectBuffer, bstrFieldName); - return VSConstants.S_OK; - case "GenerateSwitchCases": - pFunc = new SnippetFunctionGenerateSwitchCases(this, SubjectBuffer, bstrFieldName, param); - return VSConstants.S_OK; - default: - pFunc = null; - return VSConstants.E_INVALIDARG; - } - } - internal override Document AddImports( - Document document, OptionSet options, int position, XElement snippetNode, - bool allowInHiddenRegions, + Document document, AddImportPlacementOptions options, int position, XElement snippetNode, CancellationToken cancellationToken) { var importsNode = snippetNode.Element(XName.Get("Imports", snippetNode.Name.NamespaceName)); @@ -144,7 +117,7 @@ internal override Document AddImports( var addImportService = document.GetRequiredLanguageService(); var generator = document.GetRequiredLanguageService(); var compilation = document.Project.GetRequiredCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken); - var newRoot = addImportService.AddImports(compilation, root, contextLocation, newUsingDirectives, generator, options, allowInHiddenRegions, cancellationToken); + var newRoot = addImportService.AddImports(compilation, root, contextLocation, newUsingDirectives, generator, options, cancellationToken); var newDocument = document.WithSyntaxRoot(newRoot); diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionClassName.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionClassName.cs deleted file mode 100644 index 94a9f0e0c2745..0000000000000 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionClassName.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. - -#nullable disable - -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets; -using Microsoft.VisualStudio.Text; - -namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets.SnippetFunctions -{ - internal sealed class SnippetFunctionClassName : AbstractSnippetFunctionClassName - { - public SnippetFunctionClassName(SnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string fieldName) - : base(snippetExpansionClient, subjectBuffer, fieldName) - { - } - - protected override int GetContainingClassName(Document document, SnapshotSpan fieldSpan, CancellationToken cancellationToken, ref string value, ref int hasDefaultValue) - { - // Find the nearest enclosing type declaration and use its name - var syntaxTree = document.GetSyntaxTreeSynchronously(cancellationToken); - var type = syntaxTree.FindTokenOnLeftOfPosition(fieldSpan.Start.Position, cancellationToken).GetAncestor(); - - if (type != null) - { - value = type.Identifier.ToString(); - - if (!string.IsNullOrWhiteSpace(value)) - { - hasDefaultValue = 1; - } - } - - return VSConstants.S_OK; - } - } -} diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs deleted file mode 100644 index 59b0cff5a90a4..0000000000000 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs +++ /dev/null @@ -1,113 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Linq; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Simplification; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets.SnippetFunctions; -using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; -using TextSpan = Microsoft.CodeAnalysis.Text.TextSpan; -using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; - -namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets.SnippetFunctions -{ - internal sealed class SnippetFunctionGenerateSwitchCases : AbstractSnippetFunctionGenerateSwitchCases - { - public SnippetFunctionGenerateSwitchCases(SnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string caseGenerationLocationField, string switchExpressionField) - : base(snippetExpansionClient, subjectBuffer, caseGenerationLocationField, switchExpressionField) - { - } - - protected override string CaseFormat - { - get - { - return @"case {0}.{1}: - break; -"; - } - } - - protected override string DefaultCase - { - get - { - return @"default: - break;"; - } - } - - protected override bool TryGetEnumTypeSymbol(CancellationToken cancellationToken, out ITypeSymbol typeSymbol) - { - typeSymbol = null; - if (!TryGetDocument(out var document)) - { - return false; - } - - var surfaceBufferFieldSpan = new VsTextSpan[1]; - if (snippetExpansionClient.ExpansionSession.GetFieldSpan(SwitchExpressionField, surfaceBufferFieldSpan) != VSConstants.S_OK) - { - return false; - } - - if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out var subjectBufferFieldSpan)) - { - return false; - } - - var expressionSpan = subjectBufferFieldSpan.Span.ToTextSpan(); - - var syntaxTree = document.GetSyntaxTreeSynchronously(cancellationToken); - var token = syntaxTree.FindTokenOnRightOfPosition(expressionSpan.Start, cancellationToken); - var expressionNode = token.GetAncestor(n => n.Span == expressionSpan); - - if (expressionNode == null) - { - return false; - } - - var model = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken); - typeSymbol = model.GetTypeInfo(expressionNode, cancellationToken).Type; - - return typeSymbol != null; - } - - protected override bool TryGetSimplifiedTypeNameInCaseContext(Document document, string fullyQualifiedTypeName, string firstEnumMemberName, int startPosition, int endPosition, CancellationToken cancellationToken, out string simplifiedTypeName) - { - simplifiedTypeName = string.Empty; - var typeAnnotation = new SyntaxAnnotation(); - - var str = "case " + fullyQualifiedTypeName + "." + firstEnumMemberName + ":" + Environment.NewLine + " break;"; - var textChange = new TextChange(new TextSpan(startPosition, endPosition - startPosition), str); - var typeSpanToAnnotate = new TextSpan(startPosition + "case ".Length, fullyQualifiedTypeName.Length); - - var textWithCaseAdded = document.GetTextSynchronously(cancellationToken).WithChanges(textChange); - var documentWithCaseAdded = document.WithText(textWithCaseAdded); - - var syntaxRoot = documentWithCaseAdded.GetSyntaxRootSynchronously(cancellationToken); - var nodeToReplace = syntaxRoot.DescendantNodes().FirstOrDefault(n => n.Span == typeSpanToAnnotate); - - if (nodeToReplace == null) - { - return false; - } - - var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); - var documentWithAnnotations = documentWithCaseAdded.WithSyntaxRoot(updatedRoot); - - var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).Result; - simplifiedTypeName = simplifiedDocument.GetSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); - return true; - } - } -} diff --git a/src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs deleted file mode 100644 index 8fbfecc4beba5..0000000000000 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs +++ /dev/null @@ -1,46 +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.Linq; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Simplification; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServices.Implementation.Snippets.SnippetFunctions; -using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; - -namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets.SnippetFunctions -{ - internal sealed class SnippetFunctionSimpleTypeName : AbstractSnippetFunctionSimpleTypeName - { - public SnippetFunctionSimpleTypeName(SnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string fieldName, string fullyQualifiedName) - : base(snippetExpansionClient, subjectBuffer, fieldName, fullyQualifiedName) - { - } - - protected override bool TryGetSimplifiedTypeName(Document documentWithFullyQualifiedTypeName, TextSpan updatedTextSpan, CancellationToken cancellationToken, out string simplifiedTypeName) - { - simplifiedTypeName = string.Empty; - - var typeAnnotation = new SyntaxAnnotation(); - var syntaxRoot = documentWithFullyQualifiedTypeName.GetSyntaxRootSynchronously(cancellationToken); - var nodeToReplace = syntaxRoot.DescendantNodes().FirstOrDefault(n => n.Span == updatedTextSpan); - - if (nodeToReplace == null) - { - return false; - } - - var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); - var documentWithAnnotations = documentWithFullyQualifiedTypeName.WithSyntaxRoot(updatedRoot); - - var simplifiedDocument = Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken); - simplifiedTypeName = simplifiedDocument.GetSyntaxRootSynchronously(cancellationToken).GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); - return true; - } - } -} diff --git a/src/VisualStudio/CSharp/Impl/Utilities/CSharpParseOptionsChangingService.cs b/src/VisualStudio/CSharp/Impl/Utilities/CSharpParseOptionsChangingService.cs index 06c3954c16343..2d0851b62b7bd 100644 --- a/src/VisualStudio/CSharp/Impl/Utilities/CSharpParseOptionsChangingService.cs +++ b/src/VisualStudio/CSharp/Impl/Utilities/CSharpParseOptionsChangingService.cs @@ -38,6 +38,15 @@ public bool CanApplyChange(ParseOptions oldOptions, ParseOptions newOptions, str { return true; } + else if (newCSharpOptions.LanguageVersion == LanguageVersion.Preview) + { + // It's always fine to upgrade a project to 'preview'. This allows users to try out new features to see + // how well they work, while also explicitly putting them into a *known* unsupported state (that's what + // preview is after all). Importantly, this doesn't put them into an unrealized unsupported state (for + // example, picking some combo of a real lang version that isn't supported with their chosen framework + // version). + return true; + } else { Contract.ThrowIfFalse(LanguageVersionFacts.TryParse(maxLangVersion, out var parsedMaxLanguageVersion)); diff --git a/src/VisualStudio/CSharp/Impl/VSPackage.resx b/src/VisualStudio/CSharp/Impl/VSPackage.resx index dd11388e0fa0c..b035db12d94e0 100644 --- a/src/VisualStudio/CSharp/Impl/VSPackage.resx +++ b/src/VisualStudio/CSharp/Impl/VSPackage.resx @@ -189,6 +189,13 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf index bcb0b9dda1e3a..ad7dd29e51802 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + Upřednostňovat rozšířený vzor vlastností @@ -142,6 +142,11 @@ Upřednostňovat kontrolu hodnoty null před kontrolou typu + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching Upřednostňovat porovnávání vzorů diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf index c8727c855de95..71a98a3e6778e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + Muster für erweiterte Eigenschaften bevorzugen @@ -142,6 +142,11 @@ "NULL"-Überprüfung vor Typüberprüfung bevorzugen + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching Musterabgleich bevorzugen @@ -199,7 +204,7 @@ Insert Snippet - Ausschnitt einfügen + Schnipsel einfügen @@ -609,7 +614,7 @@ Place _code snippets in completion lists - _Codeausschnitte in Vervollständigungslisten anordnen + _Codeschnipsel in Vervollständigungslisten anordnen @@ -759,22 +764,22 @@ Always include snippets - Ausschnitte immer einschließen + Schnipsel immer einschließen Include snippets when ?-Tab is typed after an identifier - Ausschnitte einschließen, wenn ?-TAB nach einem Bezeichner eingegeben wird + Schnipsel einschließen, wenn ?-TAB nach einem Bezeichner eingegeben wird Never include snippets - Ausschnitte nie einschließen + Schnipsel nie einschließen Snippets behavior - Ausschnittverhalten + Schnipselverhalten diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf index 9f520f7aa0694..b049b114f3ff3 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + Preferir patrón de propiedad extendido @@ -142,6 +142,11 @@ Preferir comprobación "null' sobre comprobación de tipo + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching Preferir coincidencia de patrones diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf index 4b3d4bbe92c02..3ad23e9405999 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + Préférer le modèle de propriété étendue @@ -142,6 +142,11 @@ Préférer la vérification « null » à la vérification de type + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching Préférer les critères spéciaux diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf index 436467d250a55..5dee1db04072c 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + Preferisci il modello di proprietà estesa @@ -142,6 +142,11 @@ Preferisci il controllo 'null' al controllo del tipo + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching Preferisci i criteri di ricerca diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf index 74ded6521f820..2794be1c4f926 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + 拡張プロパティ パターンを優先する @@ -142,6 +142,11 @@ 型のチェックよりも 'null 値' チェックを優先する + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching パターン マッチングを優先する diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf index ae5e528b54aef..a00b926d8c86e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + 확장 속성 패턴 선호 @@ -142,6 +142,11 @@ 형식 검사보다 'null' 검사 선호 + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching 패턴 일치 선호 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf index 230dbc961c0fd..ffdd383801da2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + Preferuj wzorzec właściwości rozszerzonej @@ -142,6 +142,11 @@ Ustaw preferencje na sprawdzanie wartości „null” zamiast sprawdzania typu + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching Preferuj dopasowywanie do wzorca diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf index c5ae128b775b0..8deca32561ee2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + Prefere o padrão de propriedade estendida @@ -142,6 +142,11 @@ Preferir a verificação 'nula' à verificação de tipo + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching Preferir a correspondência de padrões diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf index c020550f114e7..2951510cf8337 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + Предпочитать расширенный шаблон свойства @@ -142,6 +142,11 @@ Предпочитать проверку "null" проверке типа + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching Предпочитать соответствие шаблону diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf index d95ae7aa6044c..120b0af84da47 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf @@ -89,7 +89,7 @@ In relational operators: < > <= >= is as == != - İlişkisel işleçleri içinde: <> = < > = == gibi! = + İlişkisel işleçleri içinde: <> = <> = == gibi! = 'is' and 'as' are C# keywords and should not be localized @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + Genişletilmiş özellik desenini tercih et @@ -142,6 +142,11 @@ Tür denetimi yerine 'null' denetimini tercih edin + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching Desen eşleştirmeyi tercih et diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf index 36757db206d37..e0465f1f22d71 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + 首选扩展属性模式 @@ -142,6 +142,11 @@ 与类型检查相比,首选 Null 检查 + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching 首选模式匹配 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf index d020b3844fde6..65752230e5835 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf @@ -124,7 +124,7 @@ Prefer extended property pattern - Prefer extended property pattern + 偏好擴充屬性模式 @@ -142,6 +142,11 @@ 建議使用 'null' 檢查而非鍵入檢查 + + Prefer parameter null checking + Prefer parameter null checking + + Prefer pattern matching 建議使用模式比對 diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf index 4a962af9237f0..ea0c528c96ef2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - Podtrhnout znovu přiřazené proměnné; + Podtrhnout znovu přiřazené proměnné; Zobrazovat vložené nápovědy; Zobrazit diagnostiku pro zavřené soubory; Vybarvit regulární výraz; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf index cdcffac650c01..d86915c6f5205 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - Neu zugewiesene Variablen unterstreichen; + Neu zugewiesene Variablen unterstreichen; Inlinehinweise anzeigen; Diagnoseinformationen für geschlossene Dateien anzeigen; Reguläre Ausdrücke farbig hervorheben; @@ -301,10 +308,10 @@ Vervollständigungsliste in Argumentlisten automatisch anzeigen (experimentell); \Übereinstimmende Teile der Vervollständigungslistenelemente anzeigen; Vervollständigungselementfilter anzeigen; Anweisung bei Semikolon automatisch abschließen; -Ausschnittverhalten; -Ausschnitte nie einschließen; -Ausschnitte immer einschließen; -Ausschnitte einschließen, wenn ?-TAB nach einem Bezeichner eingegeben wird; +Schnipselverhalten; +Schnipsel nie einschließen; +Schnipsel immer einschließen; +Schnipsel einschließen, wenn ?-TAB nach einem Bezeichner eingegeben wird; Verhalten der EINGABETASTE; Nie neue Zeile beim Drücken der EINGABETASTE einfügen; Neue Zeile beim Drücken der EINGABETASTE nur nach einem vollständig eingegebenen Wort einfügen; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf index f2b956dcf038d..838fa8ea7f5b2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - Subrayar variables reasignadas; + Subrayar variables reasignadas; Mostrar sugerencias insertadas; Mostrar diagnóstico para archivos cerrados; Colorear expresión regular; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf index 80973c927a777..02e238087189b 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - Souligner les variables réaffectées; + Souligner les variables réaffectées; Afficher les indicateurs inline; Afficher les diagnostics pour les fichiers fermés; Mettre en couleurs l'expression régulière; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf index 45c52df88d926..e357fbd6edacb 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - Sottolinea variabili riassegnate; + Sottolinea variabili riassegnate; Visualizza suggerimenti inline; Mostra diagnostica per file chiusi; Colora espressione regolare; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf index 859dec89df363..a79805c1e476e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - 再割り当てされる変数に下線を引く; + 再割り当てされる変数に下線を引く; インラインのヒントを表示する; 閉じているファイルの診断結果を表示する; 正規表現をカラー化する; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf index c44ad75ca228c..e1db2b0f103f6 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - 다시 할당된 변수에 밑줄 긋기; + 다시 할당된 변수에 밑줄 긋기; 인라인 힌트 표시; 닫힌 파일에 대한 진단 표시; 정규식 색 지정; @@ -305,10 +312,10 @@ Show items from unimported namespaces (experimental); 코드 조각 포함 안 함; 코드 조각 항상 포함; 식별자 뒤에 ?-Tab을 입력하면 코드 조각 포함; -&lt;Enter&gt; 키 동작; -&lt;Enter&gt; 키를 누를 때 새 줄 추가 안 함; -단어를 모두 입력한 후 &lt;Enter&gt; 키를 누를 때만 새 줄 추가; -&lt;Enter&gt; 키를 누를 때 항상 새 줄 추가; +<Enter> 키 동작; +<Enter> 키를 누를 때 새 줄 추가 안 함; +단어를 모두 입력한 후 <Enter> 키를 누를 때만 새 줄 추가; +<Enter> 키를 누를 때 항상 새 줄 추가; 이름 제안 표시; 가져오지 않은 네임스페이스의 항목 표시(실험적); C# IntelliSense options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf index ee5998ecfb005..7f70614c687f8 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - Podkreślaj ponownie przypisane zmienne; + Podkreślaj ponownie przypisane zmienne; Wyświetlaj wskazówki w tekście; Pokaż dane diagnostyczne dla zamkniętych plików; Koloruj wyrażenia regularne; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf index 4edf5b475cde9..0d96999463fd3 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - Variáveis reatribuídas de sublinhado; + Variáveis reatribuídas de sublinhado; Exibir as dicas embutidas; Mostrar os diagnósticos de arquivos fechados; Colorir a expressão regular; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf index df37718f316be..b8e7d76be8d13 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - Подчеркивать переназначенные переменные; + Подчеркивать переназначенные переменные; Показывать встроенные подсказки; Показывать диагностику для закрытых файлов; Выделять регулярные выражения; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf index 13a6dbd572bf5..f0a7f6d677616 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - Yeniden atanan değişkenleri altını çiz; + Yeniden atanan değişkenleri altını çiz; Satır içi ipuçlarını göster; Kapatılan dosyalara ilişkin tanılamaları göster; Normal ifadeyi renklendir; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf index 2971389876885..0448bfe7e4d14 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - 为重新分配变量添加下划线; + 为重新分配变量添加下划线; 显示内联提示; 显示对已关闭文件的诊断; 对正则表达式着色; diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf index 75c3cb917183e..827eab510dd75 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf @@ -80,10 +80,17 @@ prefer throwing properties; prefer auto properties; regex; regular expression; +Colorize regular expressions; +Highlight related components under cursor; +Report invalid regular expressions; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; Inheritance Margin; - 為重新指派的變數加上底線; + 為重新指派的變數加上底線; 顯示內嵌提示; 顯示已關閉檔案的診斷; 為規則運算式添加色彩; diff --git a/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs b/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs index f8da46c361725..585fa28a50da8 100644 --- a/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs +++ b/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs @@ -1212,5 +1212,21 @@ public static void Main() } }", "with"); } + + [Fact, Trait(Traits.Feature, Traits.Features.F1Help)] + public async Task TestDiscard() + { + await Test_KeywordAsync( +@" +class C +{ + void M() + { + [||]_ = Goo(); + } + + object Goo() => null; +}", "discard"); + } } } diff --git a/src/VisualStudio/CSharp/Test/GlyphExtensionsTests.cs b/src/VisualStudio/CSharp/Test/GlyphExtensionsTests.cs index 38cbe1e562664..63ad1cbaa475d 100644 --- a/src/VisualStudio/CSharp/Test/GlyphExtensionsTests.cs +++ b/src/VisualStudio/CSharp/Test/GlyphExtensionsTests.cs @@ -173,7 +173,7 @@ public void TestWithEventsMemberGlyph() isWithEvents: true); } - private void TestGlyph( + private static void TestGlyph( StandardGlyphGroup expectedGlyphGroup, SymbolKind kind = SymbolKind.Method, Accessibility declaredAccessibility = Accessibility.NotApplicable, diff --git a/src/VisualStudio/CSharp/Test/Interactive/Commands/ResetInteractiveTests.cs b/src/VisualStudio/CSharp/Test/Interactive/Commands/ResetInteractiveTests.cs index 0b6a6abbf4ba7..d518fac2ddfb9 100644 --- a/src/VisualStudio/CSharp/Test/Interactive/Commands/ResetInteractiveTests.cs +++ b/src/VisualStudio/CSharp/Test/Interactive/Commands/ResetInteractiveTests.cs @@ -27,7 +27,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Interactive.Commands [UseExportProvider] public class ResetInteractiveTests { - private string WorkspaceXmlStr => + private const string WorkspaceXmlStr = @" diff --git a/src/VisualStudio/CSharp/Test/Options/OptionViewModelTests.cs b/src/VisualStudio/CSharp/Test/Options/OptionViewModelTests.cs index 45074a633a532..1e62297a7f7fb 100644 --- a/src/VisualStudio/CSharp/Test/Options/OptionViewModelTests.cs +++ b/src/VisualStudio/CSharp/Test/Options/OptionViewModelTests.cs @@ -37,7 +37,7 @@ public object GetService(Type serviceType) } } - private string GetText(AbstractOptionPreviewViewModel viewModel) + private static string GetText(AbstractOptionPreviewViewModel viewModel) { return viewModel.TextViewHost.TextView.TextBuffer.CurrentSnapshot.GetText().ToString(); } diff --git a/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs b/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs index e66d827f69592..66aeb589ccf7a 100644 --- a/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs +++ b/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs @@ -96,20 +96,20 @@ public void Dispose() _persistentFolderRoot.Dispose(); } - private string GetData1(Size size) + private static string GetData1(Size size) => size == Size.Small ? SmallData1 : size == Size.Medium ? MediumData1 : size == Size.Large ? LargeData1 : ExtraLargeData1; - private string GetData2(Size size) + private static string GetData2(Size size) => size == Size.Small ? SmallData2 : size == Size.Medium ? MediumData2 : size == Size.Large ? LargeData2 : ExtraLargeData2; - private Checksum? GetChecksum1(bool withChecksum) + private static Checksum? GetChecksum1(bool withChecksum) => withChecksum ? s_checksum1 : null; - private Checksum? GetChecksum2(bool withChecksum) + private static Checksum? GetChecksum2(bool withChecksum) => withChecksum ? s_checksum2 : null; [Fact] @@ -870,7 +870,7 @@ public async Task PersistentService_ReadByteTwice(Size size, bool withChecksum, } } - private void DoSimultaneousReads(Func> read, string expectedValue) + private static void DoSimultaneousReads(Func> read, string expectedValue) { var barrier = new Barrier(NumThreads); var countdown = new CountdownEvent(NumThreads); @@ -902,7 +902,7 @@ private void DoSimultaneousReads(Func> read, string expectedValue) Assert.Equal(new List(), exceptions); } - private void DoSimultaneousWrites(Func write) + private static void DoSimultaneousWrites(Func write) { var barrier = new Barrier(NumThreads); var countdown = new CountdownEvent(NumThreads); diff --git a/src/VisualStudio/CodeLens/xlf/CodeLensVSResources.ru.xlf b/src/VisualStudio/CodeLens/xlf/CodeLensVSResources.ru.xlf index 83073118f59cc..28fc62dc00519 100644 --- a/src/VisualStudio/CodeLens/xlf/CodeLensVSResources.ru.xlf +++ b/src/VisualStudio/CodeLens/xlf/CodeLensVSResources.ru.xlf @@ -14,7 +14,7 @@ {0} reference - ссылка: {0} + Cсылок: {0} @@ -24,17 +24,17 @@ method - метод + метода property - Свойство + свойства type - тип + типа diff --git a/src/VisualStudio/Core/Def/Commands.vsct b/src/VisualStudio/Core/Def/Commands.vsct index a0e29adde0366..f6e603904ed1b 100644 --- a/src/VisualStudio/Core/Def/Commands.vsct +++ b/src/VisualStudio/Core/Def/Commands.vsct @@ -322,6 +322,16 @@ AnalysisScopeEntireSolution +